1 ////////////////////////////////////////////////////////////////////////////////
3 // Copyright (c) 2001 by Andrei Alexandrescu
4 // This code accompanies the book:
5 // Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
6 // Patterns Applied". Copyright (c) 2001. Addison-Wesley.
7 // Permission to use, copy, modify, distribute and sell this software for any
8 // purpose is hereby granted without fee, provided that the above copyright
9 // notice appear in all copies and that both that copyright notice and this
10 // permission notice appear in supporting documentation.
11 // The author or Addison-Wesley Longman make no representations about the
12 // suitability of this software for any purpose. It is provided "as is"
13 // without express or implied warranty.
14 ////////////////////////////////////////////////////////////////////////////////
15 #ifndef LOKI_THREADS_INC_
16 #define LOKI_THREADS_INC_
18 // $Id: Threads.h 902 2008-11-10 05:47:06Z rich_sposato $
21 /// @defgroup ThreadingGroup Threading
22 /// Policies to for the threading model:
25 /// - ObjectLevelLockable
26 /// - ClassLevelLockable
28 /// All classes in Loki have configurable threading model.
30 /// The macro LOKI_DEFAULT_THREADING selects the default
31 /// threading model for certain components of Loki
32 /// (it affects only default template arguments)
36 /// To use a specific threading model define
38 /// - nothing, single-theading is default
39 /// - LOKI_OBJECT_LEVEL_THREADING for object-level-threading
40 /// - LOKI_CLASS_LEVEL_THREADING for class-level-threading
42 /// \par Supported platfroms:
44 /// - Windows (windows.h)
45 /// - POSIX (pthread.h):
46 /// No recursive mutex support with pthread.
47 /// This means: calling Lock() on a Loki::Mutex twice from the
48 /// same thread before unlocking the mutex deadlocks the system.
49 /// To avoid this redesign your synchronization. See also:
50 /// http://sourceforge.net/tracker/index.php?func=detail&aid=1516182&group_id=29557&atid=396647
55 #if defined(LOKI_CLASS_LEVEL_THREADING) || defined(LOKI_OBJECT_LEVEL_THREADING)
57 #define LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL ::Loki::ClassLevelLockable
59 #if defined(LOKI_CLASS_LEVEL_THREADING) && !defined(LOKI_OBJECT_LEVEL_THREADING)
60 #define LOKI_DEFAULT_THREADING ::Loki::ClassLevelLockable
62 #define LOKI_DEFAULT_THREADING ::Loki::ObjectLevelLockable
65 #if defined(_WIN32) || defined(_WIN64)
67 #define LOKI_WINDOWS_H
70 #define LOKI_PTHREAD_H
75 #define LOKI_DEFAULT_THREADING ::Loki::SingleThreaded
76 #define LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL ::Loki::SingleThreaded
80 #ifndef LOKI_DEFAULT_MUTEX
81 #define LOKI_DEFAULT_MUTEX ::Loki::Mutex
86 #define LOKI_THREADS_MUTEX(x) CRITICAL_SECTION (x);
87 #define LOKI_THREADS_MUTEX_INIT(x) ::InitializeCriticalSection (x)
88 #define LOKI_THREADS_MUTEX_DELETE(x) ::DeleteCriticalSection (x)
89 #define LOKI_THREADS_MUTEX_LOCK(x) ::EnterCriticalSection (x)
90 #define LOKI_THREADS_MUTEX_UNLOCK(x) ::LeaveCriticalSection (x)
91 #define LOKI_THREADS_LONG LONG
92 #define LOKI_THREADS_MUTEX_CTOR(x)
94 #define LOKI_THREADS_ATOMIC_FUNCTIONS \
95 static IntType AtomicMultiply(volatile IntType& lval, const IntType val) \
97 ::EnterCriticalSection( &atomic_mutex_ ); \
99 ::LeaveCriticalSection( &atomic_mutex_ ); \
103 static IntType AtomicDivide(volatile IntType& lval, const IntType val) \
105 ::EnterCriticalSection( &atomic_mutex_ ); \
107 ::LeaveCriticalSection( &atomic_mutex_ ); \
111 static IntType AtomicIncrement(volatile IntType& lval) \
113 ::EnterCriticalSection( &atomic_mutex_ ); \
115 ::LeaveCriticalSection( &atomic_mutex_ ); \
119 static IntType AtomicDecrement(volatile IntType& lval) \
121 ::EnterCriticalSection( &atomic_mutex_ ); \
123 ::LeaveCriticalSection( &atomic_mutex_ ); \
127 static void AtomicAssign(volatile IntType& lval, const IntType val) \
128 { InterlockedExchange(&const_cast<IntType&>(lval), val); } \
130 static void AtomicAssign(IntType& lval, volatile const IntType& val) \
131 { InterlockedExchange(&lval, val); } \
133 static IntType AtomicIncrement(volatile IntType& lval, const IntType compare, bool & matches ) \
135 ::EnterCriticalSection( &atomic_mutex_ ); \
137 matches = ( lval == compare ); \
138 ::LeaveCriticalSection( &atomic_mutex_ ); \
142 static IntType AtomicDecrement(volatile IntType& lval, const IntType compare, bool & matches ) \
144 ::EnterCriticalSection( &atomic_mutex_ ); \
146 matches = ( lval == compare ); \
147 ::LeaveCriticalSection( &atomic_mutex_ ); \
151 static IntType AtomicAdd(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) \
153 ::EnterCriticalSection( &atomic_mutex_ ); \
155 matches = ( lval == compare ); \
156 ::LeaveCriticalSection( &atomic_mutex_ ); \
160 static IntType AtomicSubtract(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) \
162 ::EnterCriticalSection( &atomic_mutex_ ); \
164 matches = ( lval == compare ); \
165 ::LeaveCriticalSection( &atomic_mutex_ ); \
169 static IntType AtomicMultiply(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) \
171 ::EnterCriticalSection( &atomic_mutex_ ); \
173 matches = ( lval == compare ); \
174 ::LeaveCriticalSection( &atomic_mutex_ ); \
178 static IntType AtomicDivide(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) \
180 ::EnterCriticalSection( &atomic_mutex_ ); \
182 matches = ( lval == compare ); \
183 ::LeaveCriticalSection( &atomic_mutex_ ); \
187 #elif defined(LOKI_PTHREAD_H)
190 #define LOKI_THREADS_MUTEX(x) pthread_mutex_t (x);
192 #define LOKI_THREADS_MUTEX_INIT(x) ::pthread_mutex_init(x, 0)
194 // define to 1 to enable recursive mutex support
196 // experimental recursive mutex support
197 #define LOKI_THREADS_MUTEX_CTOR(x) : x(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
199 // no recursive mutex support
200 #define LOKI_THREADS_MUTEX_CTOR(x)
203 #define LOKI_THREADS_MUTEX_DELETE(x) ::pthread_mutex_destroy (x)
204 #define LOKI_THREADS_MUTEX_LOCK(x) ::pthread_mutex_lock (x)
205 #define LOKI_THREADS_MUTEX_UNLOCK(x) ::pthread_mutex_unlock (x)
206 #define LOKI_THREADS_LONG long
208 #define LOKI_THREADS_ATOMIC(x) \
209 pthread_mutex_lock(&atomic_mutex_); \
211 pthread_mutex_unlock(&atomic_mutex_)
213 #define LOKI_THREADS_ATOMIC_FUNCTIONS \
215 static pthread_mutex_t atomic_mutex_; \
217 static IntType AtomicMultiply(volatile IntType& lval, const IntType val) \
219 ::pthread_mutex_lock( &atomic_mutex_ ); \
221 ::pthread_mutex_unlock( &atomic_mutex_ ); \
225 static IntType AtomicDivide(volatile IntType& lval, const IntType val) \
227 ::pthread_mutex_lock( &atomic_mutex_ ); \
229 ::pthread_mutex_unlock( &atomic_mutex_ ); \
233 static IntType AtomicIncrement(volatile IntType& lval) \
235 ::pthread_mutex_lock( &atomic_mutex_ ); \
237 ::pthread_mutex_unlock( &atomic_mutex_ ); \
241 static IntType AtomicDecrement(volatile IntType& lval) \
243 ::pthread_mutex_lock( &atomic_mutex_ ); \
245 ::pthread_mutex_unlock( &atomic_mutex_ ); \
249 static void AtomicAssign(volatile IntType& lval, const IntType val) \
251 ::pthread_mutex_lock( &atomic_mutex_ ); \
253 ::pthread_mutex_unlock( &atomic_mutex_ ); \
257 static void AtomicAssign(IntType& lval, volatile const IntType& val) \
259 ::pthread_mutex_lock( &atomic_mutex_ ); \
261 ::pthread_mutex_unlock( &atomic_mutex_ ); \
265 static IntType AtomicIncrement(volatile IntType& lval, const IntType compare, bool & matches ) \
267 ::pthread_mutex_lock( &atomic_mutex_ ); \
269 matches = ( compare == lval ); \
270 ::pthread_mutex_unlock( &atomic_mutex_ ); \
274 static IntType AtomicDecrement(volatile IntType& lval, const IntType compare, bool & matches ) \
276 ::pthread_mutex_lock( &atomic_mutex_ ); \
278 matches = ( compare == lval ); \
279 ::pthread_mutex_unlock( &atomic_mutex_ ); \
282 static IntType AtomicMultiply(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) \
284 ::pthread_mutex_lock( &atomic_mutex_ ); \
286 matches = ( lval == compare ); \
287 ::pthread_mutex_unlock( &atomic_mutex_ ); \
291 static IntType AtomicDivide(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) \
293 ::pthread_mutex_lock( &atomic_mutex_ ); \
295 matches = ( lval == compare ); \
296 ::pthread_mutex_unlock( &atomic_mutex_ ); \
300 #else // single threaded
302 #define LOKI_THREADS_MUTEX(x)
303 #define LOKI_THREADS_MUTEX_INIT(x)
304 #define LOKI_THREADS_MUTEX_DELETE(x)
305 #define LOKI_THREADS_MUTEX_LOCK(x)
306 #define LOKI_THREADS_MUTEX_UNLOCK(x)
307 #define LOKI_THREADS_LONG
308 #define LOKI_THREADS_MUTEX_CTOR(x)
317 ////////////////////////////////////////////////////////////////////////////////
320 /// \ingroup ThreadingGroup
321 /// A simple and portable Mutex. A default policy class for locking objects.
322 ////////////////////////////////////////////////////////////////////////////////
327 Mutex() LOKI_THREADS_MUTEX_CTOR(mtx_)
329 LOKI_THREADS_MUTEX_INIT(&mtx_);
333 LOKI_THREADS_MUTEX_DELETE(&mtx_);
337 LOKI_THREADS_MUTEX_LOCK(&mtx_);
341 LOKI_THREADS_MUTEX_UNLOCK(&mtx_);
344 /// Copy-constructor not implemented.
345 Mutex(const Mutex &);
346 /// Copy-assignement operator not implemented.
347 Mutex &operator = (const Mutex &);
348 LOKI_THREADS_MUTEX(mtx_)
352 ////////////////////////////////////////////////////////////////////////////////
353 /// \class SingleThreaded
355 /// \ingroup ThreadingGroup
356 /// Implementation of the ThreadingModel policy used by various classes
357 /// Implements a single-threaded model; no synchronization
358 ////////////////////////////////////////////////////////////////////////////////
359 template <class Host, class MutexPolicy = LOKI_DEFAULT_MUTEX>
368 explicit Lock(const SingleThreaded &) {}
369 explicit Lock(const SingleThreaded *) {}
372 typedef Host VolatileType;
376 static IntType AtomicAdd(volatile IntType &lval, const IntType val)
381 static IntType AtomicSubtract(volatile IntType &lval, const IntType val)
386 static IntType AtomicMultiply(volatile IntType &lval, const IntType val)
391 static IntType AtomicDivide(volatile IntType &lval, const IntType val)
396 static IntType AtomicIncrement(volatile IntType &lval)
401 static IntType AtomicDecrement(volatile IntType &lval)
406 static void AtomicAssign(volatile IntType &lval, const IntType val)
411 static void AtomicAssign(IntType &lval, volatile IntType &val)
416 static IntType AtomicAdd(volatile IntType &lval, const IntType val, const IntType compare, bool &matches )
419 matches = ( lval == compare );
423 static IntType AtomicSubtract(volatile IntType &lval, const IntType val, const IntType compare, bool &matches )
426 matches = ( lval == compare );
430 static IntType AtomicMultiply(volatile IntType &lval, const IntType val, const IntType compare, bool &matches )
433 matches = ( lval == compare );
437 static IntType AtomicDivide(volatile IntType &lval, const IntType val, const IntType compare, bool &matches )
440 matches = ( lval == compare );
444 static IntType AtomicIncrement(volatile IntType &lval, const IntType compare, bool &matches )
447 matches = ( lval == compare );
451 static IntType AtomicDecrement(volatile IntType &lval, const IntType compare, bool &matches )
454 matches = ( lval == compare );
461 #if defined(LOKI_WINDOWS_H) || defined(LOKI_PTHREAD_H)
463 ////////////////////////////////////////////////////////////////////////////////
464 /// \class ObjectLevelLockable
466 /// \ingroup ThreadingGroup
467 /// Implementation of the ThreadingModel policy used by various classes
468 /// Implements a object-level locking scheme
469 ////////////////////////////////////////////////////////////////////////////////
470 template < class Host, class MutexPolicy = LOKI_DEFAULT_MUTEX >
471 class ObjectLevelLockable
473 mutable MutexPolicy mtx_;
476 ObjectLevelLockable() : mtx_() {}
478 ObjectLevelLockable(const ObjectLevelLockable &) : mtx_() {}
480 ~ObjectLevelLockable() {}
486 /// Lock class to lock on object level
492 explicit Lock(const ObjectLevelLockable &host) : host_(host)
498 explicit Lock(const ObjectLevelLockable *host) : host_(*host)
510 /// private by design of the object level threading
513 Lock &operator=(const Lock &);
514 const ObjectLevelLockable &host_;
517 typedef volatile Host VolatileType;
519 typedef LOKI_THREADS_LONG IntType;
521 LOKI_THREADS_ATOMIC_FUNCTIONS
525 #ifdef LOKI_PTHREAD_H
526 template <class Host, class MutexPolicy>
527 pthread_mutex_t ObjectLevelLockable<Host, MutexPolicy>::atomic_mutex_ = PTHREAD_MUTEX_INITIALIZER;
530 ////////////////////////////////////////////////////////////////////////////////
531 /// \class ClassLevelLockable
533 /// \ingroup ThreadingGroup
534 /// Implementation of the ThreadingModel policy used by various classes
535 /// Implements a class-level locking scheme
536 ////////////////////////////////////////////////////////////////////////////////
537 template <class Host, class MutexPolicy = LOKI_DEFAULT_MUTEX >
538 class ClassLevelLockable
545 Initializer() : init_(false), mtx_()
556 static Initializer initializer_;
564 /// Lock class to lock on class level
572 assert(initializer_.init_);
573 initializer_.mtx_.Lock();
577 explicit Lock(const ClassLevelLockable &)
579 assert(initializer_.init_);
580 initializer_.mtx_.Lock();
584 explicit Lock(const ClassLevelLockable *)
586 assert(initializer_.init_);
587 initializer_.mtx_.Lock();
593 assert(initializer_.init_);
594 initializer_.mtx_.Unlock();
599 Lock &operator=(const Lock &);
602 typedef volatile Host VolatileType;
604 typedef LOKI_THREADS_LONG IntType;
606 LOKI_THREADS_ATOMIC_FUNCTIONS
610 #ifdef LOKI_PTHREAD_H
611 template <class Host, class MutexPolicy>
612 pthread_mutex_t ClassLevelLockable<Host, MutexPolicy>::atomic_mutex_ = PTHREAD_MUTEX_INITIALIZER;
615 template < class Host, class MutexPolicy >
616 typename ClassLevelLockable< Host, MutexPolicy >::Initializer
617 ClassLevelLockable< Host, MutexPolicy >::initializer_;
619 #endif // #if defined(LOKI_WINDOWS_H) || defined(LOKI_PTHREAD_H)
624 #endif // end file guardian