]> git.cworth.org Git - vogl/blob - src/extlib/loki/include/loki/Threads.h
Initial vogl checkin
[vogl] / src / extlib / loki / include / loki / Threads.h
1 ////////////////////////////////////////////////////////////////////////////////
2 // The Loki Library
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_
17
18 // $Id: Threads.h 902 2008-11-10 05:47:06Z rich_sposato $
19
20
21 ///  @defgroup  ThreadingGroup Threading
22 ///  Policies to for the threading model:
23 ///
24 ///  - SingleThreaded
25 ///  - ObjectLevelLockable
26 ///  - ClassLevelLockable
27 ///
28 ///  All classes in Loki have configurable threading model.
29 ///
30 ///  The macro LOKI_DEFAULT_THREADING selects the default
31 ///  threading model for certain components of Loki
32 ///  (it affects only default template arguments)
33 ///
34 ///  \par Usage:
35 ///
36 ///  To use a specific threading model define
37 ///
38 ///  - nothing, single-theading is default
39 ///  - LOKI_OBJECT_LEVEL_THREADING for object-level-threading
40 ///  - LOKI_CLASS_LEVEL_THREADING for class-level-threading
41 ///
42 ///  \par Supported platfroms:
43 ///
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
51
52
53 #include <cassert>
54
55 #if defined(LOKI_CLASS_LEVEL_THREADING) || defined(LOKI_OBJECT_LEVEL_THREADING)
56
57 #define LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL ::Loki::ClassLevelLockable
58
59 #if defined(LOKI_CLASS_LEVEL_THREADING) && !defined(LOKI_OBJECT_LEVEL_THREADING)
60 #define LOKI_DEFAULT_THREADING ::Loki::ClassLevelLockable
61 #else
62 #define LOKI_DEFAULT_THREADING ::Loki::ObjectLevelLockable
63 #endif
64
65 #if defined(_WIN32) || defined(_WIN64)
66 #include <windows.h>
67 #define LOKI_WINDOWS_H
68 #else
69 #include <pthread.h>
70 #define LOKI_PTHREAD_H
71 #endif
72
73 #else
74
75 #define LOKI_DEFAULT_THREADING ::Loki::SingleThreaded
76 #define LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL ::Loki::SingleThreaded
77
78 #endif
79
80 #ifndef LOKI_DEFAULT_MUTEX
81 #define LOKI_DEFAULT_MUTEX ::Loki::Mutex
82 #endif
83
84 #ifdef LOKI_WINDOWS_H
85
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)
93
94 #define LOKI_THREADS_ATOMIC_FUNCTIONS                                   \
95         static IntType AtomicMultiply(volatile IntType& lval, const IntType val) \
96         {                                                               \
97             ::EnterCriticalSection( &atomic_mutex_ );                   \
98             lval *= val;                                                \
99             ::LeaveCriticalSection( &atomic_mutex_ );                   \
100             return lval;                                                \
101         }                                                               \
102                                                                         \
103         static IntType AtomicDivide(volatile IntType& lval, const IntType val)  \
104         {                                                               \
105             ::EnterCriticalSection( &atomic_mutex_ );                   \
106             lval /= val;                                                \
107             ::LeaveCriticalSection( &atomic_mutex_ );                   \
108             return lval;                                                \
109         }                                                               \
110                                                                         \
111         static IntType AtomicIncrement(volatile IntType& lval)          \
112         {                                                               \
113             ::EnterCriticalSection( &atomic_mutex_ );                   \
114             ++lval;                                                     \
115             ::LeaveCriticalSection( &atomic_mutex_ );                   \
116             return lval;                                                \
117         }                                                               \
118                                                                         \
119         static IntType AtomicDecrement(volatile IntType& lval)          \
120         {                                                               \
121             ::EnterCriticalSection( &atomic_mutex_ );                   \
122             --lval;                                                     \
123             ::LeaveCriticalSection( &atomic_mutex_ );                   \
124             return lval;                                                \
125         }                                                               \
126                                                                         \
127         static void AtomicAssign(volatile IntType& lval, const IntType val)   \
128         { InterlockedExchange(&const_cast<IntType&>(lval), val); }      \
129                                                                         \
130         static void AtomicAssign(IntType& lval, volatile const IntType& val)  \
131         { InterlockedExchange(&lval, val); }                            \
132                                                                         \
133         static IntType AtomicIncrement(volatile IntType& lval, const IntType compare, bool & matches )  \
134         {                                                               \
135             ::EnterCriticalSection( &atomic_mutex_ );                   \
136             ++lval;                                                     \
137             matches = ( lval == compare );                              \
138             ::LeaveCriticalSection( &atomic_mutex_ );                   \
139             return lval;                                                \
140         }                                                               \
141                                                                         \
142         static IntType AtomicDecrement(volatile IntType& lval, const IntType compare, bool & matches )  \
143         {                                                               \
144             ::EnterCriticalSection( &atomic_mutex_ );                   \
145             --lval;                                                     \
146             matches = ( lval == compare );                              \
147             ::LeaveCriticalSection( &atomic_mutex_ );                   \
148             return lval;                                                \
149         }                                                               \
150                                                                         \
151         static IntType AtomicAdd(volatile IntType& lval, const IntType val, const IntType compare, bool & matches )  \
152         {                                                               \
153             ::EnterCriticalSection( &atomic_mutex_ );                   \
154             lval += val;                                                \
155             matches = ( lval == compare );                              \
156             ::LeaveCriticalSection( &atomic_mutex_ );                   \
157             return lval;                                                \
158         }                                                               \
159                                                                         \
160         static IntType AtomicSubtract(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) \
161         {                                                               \
162             ::EnterCriticalSection( &atomic_mutex_ );                   \
163             lval -= val;                                                \
164             matches = ( lval == compare );                              \
165             ::LeaveCriticalSection( &atomic_mutex_ );                   \
166             return lval;                                                \
167         }                                                               \
168                                                                         \
169         static IntType AtomicMultiply(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) \
170         {                                                               \
171             ::EnterCriticalSection( &atomic_mutex_ );                   \
172             lval *= val;                                                \
173             matches = ( lval == compare );                              \
174             ::LeaveCriticalSection( &atomic_mutex_ );                   \
175             return lval;                                                \
176         }                                                               \
177                                                                         \
178         static IntType AtomicDivide(volatile IntType& lval, const IntType val, const IntType compare, bool & matches )   \
179         {                                                               \
180             ::EnterCriticalSection( &atomic_mutex_ );                    \
181             lval /= val;                                                \
182             matches = ( lval == compare );                              \
183             ::LeaveCriticalSection( &atomic_mutex_ );                    \
184             return lval;                                                \
185         }
186
187 #elif defined(LOKI_PTHREAD_H)
188
189
190 #define LOKI_THREADS_MUTEX(x)           pthread_mutex_t (x);
191
192 #define LOKI_THREADS_MUTEX_INIT(x)      ::pthread_mutex_init(x, 0)
193
194 // define to 1 to enable recursive mutex support
195 #if 0
196 // experimental recursive mutex support
197 #define LOKI_THREADS_MUTEX_CTOR(x)      : x(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
198 #else
199 // no recursive mutex support
200 #define LOKI_THREADS_MUTEX_CTOR(x)
201 #endif
202
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
207
208 #define LOKI_THREADS_ATOMIC(x)                                           \
209                 pthread_mutex_lock(&atomic_mutex_);                      \
210                 x;                                                       \
211                 pthread_mutex_unlock(&atomic_mutex_)
212
213 #define LOKI_THREADS_ATOMIC_FUNCTIONS                                \
214     private:                                                         \
215         static pthread_mutex_t atomic_mutex_;                        \
216     public:                                                          \
217         static IntType AtomicMultiply(volatile IntType& lval, const IntType val) \
218         {                                                                \
219             ::pthread_mutex_lock( &atomic_mutex_ );                      \
220             lval *= val;                                                 \
221             ::pthread_mutex_unlock( &atomic_mutex_ );                    \
222             return lval;                                                 \
223         }                                                                \
224                                                                          \
225         static IntType AtomicDivide(volatile IntType& lval, const IntType val) \
226         {                                                                \
227             ::pthread_mutex_lock( &atomic_mutex_ );                      \
228             lval /= val;                                                 \
229             ::pthread_mutex_unlock( &atomic_mutex_ );                    \
230             return lval;                                                 \
231         }                                                                \
232                                                                          \
233         static IntType AtomicIncrement(volatile IntType& lval)           \
234         {                                                                \
235             ::pthread_mutex_lock( &atomic_mutex_ );                      \
236             ++lval;                                                      \
237             ::pthread_mutex_unlock( &atomic_mutex_ );                    \
238             return lval;                                                 \
239         }                                                                \
240                                                                          \
241         static IntType AtomicDecrement(volatile IntType& lval)           \
242         {                                                                \
243             ::pthread_mutex_lock( &atomic_mutex_ );                      \
244             --lval;                                                      \
245             ::pthread_mutex_unlock( &atomic_mutex_ );                    \
246             return lval;                                                 \
247         }                                                                \
248                                                                          \
249         static void AtomicAssign(volatile IntType& lval, const IntType val) \
250         {                                                                \
251             ::pthread_mutex_lock( &atomic_mutex_ );                      \
252             lval = val;                                                  \
253             ::pthread_mutex_unlock( &atomic_mutex_ );                    \
254             return lval;                                                 \
255         }                                                                \
256                                                                          \
257         static void AtomicAssign(IntType& lval, volatile const IntType& val) \
258         {                                                                \
259             ::pthread_mutex_lock( &atomic_mutex_ );                      \
260             lval = val;                                                  \
261             ::pthread_mutex_unlock( &atomic_mutex_ );                    \
262             return lval;                                                 \
263         }                                                                \
264                                                                          \
265         static IntType AtomicIncrement(volatile IntType& lval, const IntType compare, bool & matches ) \
266         {                                                                \
267             ::pthread_mutex_lock( &atomic_mutex_ );                      \
268             ++lval;                                                      \
269             matches = ( compare == lval );                               \
270             ::pthread_mutex_unlock( &atomic_mutex_ );                    \
271             return lval;                                                 \
272         }                                                                \
273                                                                          \
274         static IntType AtomicDecrement(volatile IntType& lval, const IntType compare, bool & matches ) \
275         {                                                                \
276             ::pthread_mutex_lock( &atomic_mutex_ );                      \
277             --lval;                                                      \
278             matches = ( compare == lval );                               \
279             ::pthread_mutex_unlock( &atomic_mutex_ );                    \
280             return lval;                                                 \
281         }                                                                \
282         static IntType AtomicMultiply(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) \
283         {                                                               \
284             ::pthread_mutex_lock( &atomic_mutex_ );                     \
285             lval *= val;                                                \
286             matches = ( lval == compare );                              \
287             ::pthread_mutex_unlock( &atomic_mutex_ );                   \
288             return lval;                                                \
289         }                                                               \
290                                                                         \
291         static IntType AtomicDivide(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) \
292         {                                                               \
293             ::pthread_mutex_lock( &atomic_mutex_ );                     \
294             lval /= val;                                                \
295             matches = ( lval == compare );                              \
296             ::pthread_mutex_unlock( &atomic_mutex_ );                   \
297             return lval;                                                \
298         }
299
300 #else // single threaded
301
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)
309
310 #endif
311
312
313
314 namespace Loki
315 {
316
317 ////////////////////////////////////////////////////////////////////////////////
318 ///  \class Mutex
319 //
320 ///  \ingroup ThreadingGroup
321 ///  A simple and portable Mutex.  A default policy class for locking objects.
322 ////////////////////////////////////////////////////////////////////////////////
323
324 class Mutex
325 {
326 public:
327         Mutex() LOKI_THREADS_MUTEX_CTOR(mtx_)
328         {
329                 LOKI_THREADS_MUTEX_INIT(&mtx_);
330         }
331         ~Mutex()
332         {
333                 LOKI_THREADS_MUTEX_DELETE(&mtx_);
334         }
335         void Lock()
336         {
337                 LOKI_THREADS_MUTEX_LOCK(&mtx_);
338         }
339         void Unlock()
340         {
341                 LOKI_THREADS_MUTEX_UNLOCK(&mtx_);
342         }
343 private:
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_)
349 };
350
351
352 ////////////////////////////////////////////////////////////////////////////////
353 ///  \class SingleThreaded
354 ///
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>
360 class SingleThreaded
361 {
362 public:
363         /// \struct Lock
364         /// Dummy Lock class
365         struct Lock
366         {
367                 Lock() {}
368                 explicit Lock(const SingleThreaded &) {}
369                 explicit Lock(const SingleThreaded *) {}
370         };
371
372         typedef Host VolatileType;
373
374         typedef int IntType;
375
376         static IntType AtomicAdd(volatile IntType &lval, const IntType val)
377         {
378                 return lval += val;
379         }
380
381         static IntType AtomicSubtract(volatile IntType &lval, const IntType val)
382         {
383                 return lval -= val;
384         }
385
386         static IntType AtomicMultiply(volatile IntType &lval, const IntType val)
387         {
388                 return lval *= val;
389         }
390
391         static IntType AtomicDivide(volatile IntType &lval, const IntType val)
392         {
393                 return lval /= val;
394         }
395
396         static IntType AtomicIncrement(volatile IntType &lval)
397         {
398                 return ++lval;
399         }
400
401         static IntType AtomicDecrement(volatile IntType &lval)
402         {
403                 return --lval;
404         }
405
406         static void AtomicAssign(volatile IntType &lval, const IntType val)
407         {
408                 lval = val;
409         }
410
411         static void AtomicAssign(IntType &lval, volatile IntType &val)
412         {
413                 lval = val;
414         }
415
416         static IntType AtomicAdd(volatile IntType &lval, const IntType val, const IntType compare, bool &matches )
417         {
418                 lval += val;
419                 matches = ( lval == compare );
420                 return lval;
421         }
422
423         static IntType AtomicSubtract(volatile IntType &lval, const IntType val, const IntType compare, bool &matches )
424         {
425                 lval -= val;
426                 matches = ( lval == compare );
427                 return lval;
428         }
429
430         static IntType AtomicMultiply(volatile IntType &lval, const IntType val, const IntType compare, bool &matches )
431         {
432                 lval *= val;
433                 matches = ( lval == compare );
434                 return lval;
435         }
436
437         static IntType AtomicDivide(volatile IntType &lval, const IntType val, const IntType compare, bool &matches )
438         {
439                 lval /= val;
440                 matches = ( lval == compare );
441                 return lval;
442         }
443
444         static IntType AtomicIncrement(volatile IntType &lval, const IntType compare, bool &matches )
445         {
446                 ++lval;
447                 matches = ( lval == compare );
448                 return lval;
449         }
450
451         static IntType AtomicDecrement(volatile IntType &lval, const IntType compare, bool &matches )
452         {
453                 --lval;
454                 matches = ( lval == compare );
455                 return lval;
456         }
457
458 };
459
460
461 #if defined(LOKI_WINDOWS_H) || defined(LOKI_PTHREAD_H)
462
463 ////////////////////////////////////////////////////////////////////////////////
464 ///  \class ObjectLevelLockable
465 ///
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
472 {
473         mutable MutexPolicy mtx_;
474
475 public:
476         ObjectLevelLockable() : mtx_() {}
477
478         ObjectLevelLockable(const ObjectLevelLockable &) : mtx_() {}
479
480         ~ObjectLevelLockable() {}
481
482         class Lock;
483         friend class Lock;
484
485         ///  \struct Lock
486         ///  Lock class to lock on object level
487         class Lock
488         {
489         public:
490
491                 /// Lock object
492                 explicit Lock(const ObjectLevelLockable &host) : host_(host)
493                 {
494                         host_.mtx_.Lock();
495                 }
496
497                 /// Lock object
498                 explicit Lock(const ObjectLevelLockable *host) : host_(*host)
499                 {
500                         host_.mtx_.Lock();
501                 }
502
503                 /// Unlock object
504                 ~Lock()
505                 {
506                         host_.mtx_.Unlock();
507                 }
508
509         private:
510                 /// private by design of the object level threading
511                 Lock();
512                 Lock(const Lock &);
513                 Lock &operator=(const Lock &);
514                 const ObjectLevelLockable &host_;
515         };
516
517         typedef volatile Host VolatileType;
518
519         typedef LOKI_THREADS_LONG IntType;
520
521         LOKI_THREADS_ATOMIC_FUNCTIONS
522
523 };
524
525 #ifdef LOKI_PTHREAD_H
526 template <class Host, class MutexPolicy>
527 pthread_mutex_t ObjectLevelLockable<Host, MutexPolicy>::atomic_mutex_ = PTHREAD_MUTEX_INITIALIZER;
528 #endif
529
530 ////////////////////////////////////////////////////////////////////////////////
531 ///  \class ClassLevelLockable
532 ///
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
539 {
540         struct Initializer
541         {
542                 bool init_;
543                 MutexPolicy mtx_;
544
545                 Initializer() : init_(false), mtx_()
546                 {
547                         init_ = true;
548                 }
549
550                 ~Initializer()
551                 {
552                         assert(init_);
553                 }
554         };
555
556         static Initializer initializer_;
557
558 public:
559
560         class Lock;
561         friend class Lock;
562
563         ///  \struct Lock
564         ///  Lock class to lock on class level
565         class Lock
566         {
567         public:
568
569                 /// Lock class
570                 Lock()
571                 {
572                         assert(initializer_.init_);
573                         initializer_.mtx_.Lock();
574                 }
575
576                 /// Lock class
577                 explicit Lock(const ClassLevelLockable &)
578                 {
579                         assert(initializer_.init_);
580                         initializer_.mtx_.Lock();
581                 }
582
583                 /// Lock class
584                 explicit Lock(const ClassLevelLockable *)
585                 {
586                         assert(initializer_.init_);
587                         initializer_.mtx_.Lock();
588                 }
589
590                 /// Unlock class
591                 ~Lock()
592                 {
593                         assert(initializer_.init_);
594                         initializer_.mtx_.Unlock();
595                 }
596
597         private:
598                 Lock(const Lock &);
599                 Lock &operator=(const Lock &);
600         };
601
602         typedef volatile Host VolatileType;
603
604         typedef LOKI_THREADS_LONG IntType;
605
606         LOKI_THREADS_ATOMIC_FUNCTIONS
607
608 };
609
610 #ifdef LOKI_PTHREAD_H
611 template <class Host, class MutexPolicy>
612 pthread_mutex_t ClassLevelLockable<Host, MutexPolicy>::atomic_mutex_ = PTHREAD_MUTEX_INITIALIZER;
613 #endif
614
615 template < class Host, class MutexPolicy >
616 typename ClassLevelLockable< Host, MutexPolicy >::Initializer
617 ClassLevelLockable< Host, MutexPolicy >::initializer_;
618
619 #endif // #if defined(LOKI_WINDOWS_H) || defined(LOKI_PTHREAD_H)
620
621 } // namespace Loki
622
623
624 #endif // end file guardian
625