Threads.h

00001 
00002 // The Loki Library
00003 // Copyright (c) 2001 by Andrei Alexandrescu
00004 // This code accompanies the book:
00005 // Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design 
00006 //     Patterns Applied". Copyright (c) 2001. Addison-Wesley.
00007 // Permission to use, copy, modify, distribute and sell this software for any 
00008 //     purpose is hereby granted without fee, provided that the above copyright 
00009 //     notice appear in all copies and that both that copyright notice and this 
00010 //     permission notice appear in supporting documentation.
00011 // The author or Addison-Wesley Longman make no representations about the 
00012 //     suitability of this software for any purpose. It is provided "as is" 
00013 //     without express or implied warranty.
00015 #ifndef LOKI_THREADS_INC_
00016 #define LOKI_THREADS_INC_
00017 
00018 // $Id: Threads.h 749 2006-10-17 19:49:26Z syntheticpp $
00019 
00020 
00051 
00052 
00053 #include <cassert>
00054 
00055 #if defined(LOKI_CLASS_LEVEL_THREADING) || defined(LOKI_OBJECT_LEVEL_THREADING)
00056 
00057     #define LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL ::Loki::ClassLevelLockable
00058     
00059     #if defined(LOKI_CLASS_LEVEL_THREADING) && !defined(LOKI_OBJECT_LEVEL_THREADING)
00060         #define LOKI_DEFAULT_THREADING ::Loki::ClassLevelLockable
00061     #else
00062         #define LOKI_DEFAULT_THREADING ::Loki::ObjectLevelLockable
00063     #endif
00064      
00065     #if defined(_WIN32) || defined(_WIN64)
00066         #include <windows.h> 
00067         #define LOKI_WINDOWS_H
00068     #else
00069         #include <pthread.h>
00070         #define LOKI_PTHREAD_H
00071     #endif
00072     
00073 #else
00074 
00075     #define LOKI_DEFAULT_THREADING ::Loki::SingleThreaded
00076     #define LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL ::Loki::SingleThreaded
00077     
00078 #endif
00079     
00080 #ifndef LOKI_DEFAULT_MUTEX
00081 #define LOKI_DEFAULT_MUTEX ::Loki::Mutex
00082 #endif
00083 
00084 #ifdef LOKI_WINDOWS_H
00085 
00086 #define LOKI_THREADS_MUTEX(x)           CRITICAL_SECTION (x);
00087 #define LOKI_THREADS_MUTEX_INIT(x)      ::InitializeCriticalSection (x)
00088 #define LOKI_THREADS_MUTEX_DELETE(x)    ::DeleteCriticalSection (x)
00089 #define LOKI_THREADS_MUTEX_LOCK(x)      ::EnterCriticalSection (x)
00090 #define LOKI_THREADS_MUTEX_UNLOCK(x)    ::LeaveCriticalSection (x)
00091 #define LOKI_THREADS_LONG               LONG
00092 
00093 #define LOKI_THREADS_ATOMIC_FUNCTIONS                                   \
00094         static IntType AtomicIncrement(volatile IntType& lval)          \
00095         { return InterlockedIncrement(&const_cast<IntType&>(lval)); }   \
00096                                                                         \
00097         static IntType AtomicDecrement(volatile IntType& lval)          \
00098         { return InterlockedDecrement(&const_cast<IntType&>(lval)); }   \
00099                                                                         \
00100         static void AtomicAssign(volatile IntType& lval, IntType val)   \
00101         { InterlockedExchange(&const_cast<IntType&>(lval), val); }      \
00102                                                                         \
00103         static void AtomicAssign(IntType& lval, volatile IntType& val)  \
00104         { InterlockedExchange(&lval, val); }
00105 
00106 
00107 
00108 #elif defined(LOKI_PTHREAD_H)
00109 
00110 
00111 #define LOKI_THREADS_MUTEX(x)           pthread_mutex_t (x);
00112 
00113 // no recursive mutex support
00114 #define LOKI_THREADS_MUTEX_INIT(x)      ::pthread_mutex_init(x, 0)
00115 
00116 #define LOKI_THREADS_MUTEX_DELETE(x)    ::pthread_mutex_destroy (x)
00117 #define LOKI_THREADS_MUTEX_LOCK(x)      ::pthread_mutex_lock (x)
00118 #define LOKI_THREADS_MUTEX_UNLOCK(x)    ::pthread_mutex_unlock (x)
00119 #define LOKI_THREADS_LONG               long
00120 
00121 #define LOKI_THREADS_ATOMIC(x)                                           \
00122                 pthread_mutex_lock(&atomic_mutex_);                      \
00123                 x;                                                       \
00124                 pthread_mutex_unlock(&atomic_mutex_)    
00125                 
00126 #define LOKI_THREADS_ATOMIC_FUNCTIONS                                    \
00127         private:                                                         \
00128             static pthread_mutex_t atomic_mutex_;                        \
00129         public:                                                          \
00130         static IntType AtomicIncrement(volatile IntType& lval)           \
00131         { LOKI_THREADS_ATOMIC( lval++ ); return lval; }                  \
00132                                                                          \
00133         static IntType AtomicDecrement(volatile IntType& lval)           \
00134         { LOKI_THREADS_ATOMIC(lval-- ); return lval; }                   \
00135                                                                          \
00136         static void AtomicAssign(volatile IntType& lval, IntType val)    \
00137         { LOKI_THREADS_ATOMIC( lval = val ); }                           \
00138                                                                          \
00139         static void AtomicAssign(IntType& lval, volatile IntType& val)   \
00140         { LOKI_THREADS_ATOMIC( lval = val ); }            
00141 
00142 #else // single threaded
00143 
00144 #define LOKI_THREADS_MUTEX(x)
00145 #define LOKI_THREADS_MUTEX_INIT(x)      
00146 #define LOKI_THREADS_MUTEX_DELETE(x)       
00147 #define LOKI_THREADS_MUTEX_LOCK(x)         
00148 #define LOKI_THREADS_MUTEX_UNLOCK(x)       
00149 #define LOKI_THREADS_LONG               
00150 
00151 #endif
00152 
00153 
00154 
00155 namespace Loki
00156 {
00157 
00160     //
00164 
00165     class Mutex
00166     {
00167     public:
00168         Mutex()
00169         {
00170             LOKI_THREADS_MUTEX_INIT(&mtx_);
00171         }
00172         ~Mutex()
00173         {
00174             LOKI_THREADS_MUTEX_DELETE(&mtx_);
00175         }
00176         void Lock()
00177         {
00178             LOKI_THREADS_MUTEX_LOCK(&mtx_);
00179         }
00180         void Unlock()
00181         {
00182             LOKI_THREADS_MUTEX_UNLOCK(&mtx_);
00183         }
00184     private:
00186         Mutex(const Mutex &);
00188         Mutex & operator = (const Mutex &);
00189         LOKI_THREADS_MUTEX(mtx_)
00190     };
00191 
00192 
00200     template <class Host, class MutexPolicy = LOKI_DEFAULT_MUTEX>
00201     class SingleThreaded
00202     {
00203     public:
00206         struct Lock
00207         {
00208             Lock() {}
00209             explicit Lock(const SingleThreaded&) {}
00210             explicit Lock(const SingleThreaded*) {}
00211         };
00212         
00213         typedef Host VolatileType;
00214 
00215         typedef int IntType; 
00216 
00217         static IntType AtomicAdd(volatile IntType& lval, IntType val)
00218         { return lval += val; }
00219         
00220         static IntType AtomicSubtract(volatile IntType& lval, IntType val)
00221         { return lval -= val; }
00222 
00223         static IntType AtomicMultiply(volatile IntType& lval, IntType val)
00224         { return lval *= val; }
00225         
00226         static IntType AtomicDivide(volatile IntType& lval, IntType val)
00227         { return lval /= val; }
00228         
00229         static IntType AtomicIncrement(volatile IntType& lval)
00230         { return ++lval; }
00231         
00232         static IntType AtomicDecrement(volatile IntType& lval)
00233         { return --lval; }
00234         
00235         static void AtomicAssign(volatile IntType & lval, IntType val)
00236         { lval = val; }
00237         
00238         static void AtomicAssign(IntType & lval, volatile IntType & val)
00239         { lval = val; }
00240     };
00241     
00242 
00243 #if defined(LOKI_WINDOWS_H) || defined(LOKI_PTHREAD_H) 
00244 
00252     template < class Host, class MutexPolicy = LOKI_DEFAULT_MUTEX >
00253     class ObjectLevelLockable
00254     {
00255         mutable MutexPolicy mtx_;
00256 
00257     public:
00258         ObjectLevelLockable() : mtx_() {}
00259 
00260         ObjectLevelLockable(const ObjectLevelLockable&) : mtx_() {}
00261 
00262         ~ObjectLevelLockable() {}
00263 
00264         class Lock;
00265         friend class Lock;
00266         
00269         class Lock
00270         { 
00271         public:
00272             
00274             explicit Lock(const ObjectLevelLockable& host) : host_(host)
00275             {
00276                 host_.mtx_.Lock();
00277             }
00278 
00280             explicit Lock(const ObjectLevelLockable* host) : host_(*host)
00281             {
00282                 host_.mtx_.Lock();
00283             }
00284 
00286             ~Lock()
00287             {
00288                 host_.mtx_.Unlock();
00289             }
00290 
00291         private:
00293             Lock();
00294             Lock(const Lock&);
00295             Lock& operator=(const Lock&);
00296             const ObjectLevelLockable& host_;
00297         };
00298 
00299         typedef volatile Host VolatileType;
00300 
00301         typedef LOKI_THREADS_LONG IntType; 
00302         
00303         LOKI_THREADS_ATOMIC_FUNCTIONS   
00304         
00305     };
00306 
00307 #ifdef LOKI_PTHREAD_H
00308     template <class Host, class MutexPolicy>
00309     pthread_mutex_t ObjectLevelLockable<Host, MutexPolicy>::atomic_mutex_ = PTHREAD_MUTEX_INITIALIZER;
00310 #endif
00311     
00319     template <class Host, class MutexPolicy = LOKI_DEFAULT_MUTEX >
00320     class ClassLevelLockable
00321     {
00322         struct Initializer
00323         {   
00324             bool init_;
00325             MutexPolicy mtx_;
00326 
00327             Initializer() : init_(false), mtx_()
00328             {
00329                 init_ = true;
00330             }
00331 
00332             ~Initializer()
00333             {
00334                 assert(init_);
00335             }
00336         };
00337 
00338         static Initializer initializer_;
00339 
00340     public:
00341 
00342         class Lock;
00343         friend class Lock;
00344 
00347         class Lock
00348         {    
00349         public:
00350 
00352             Lock()
00353             {
00354                 assert(initializer_.init_);
00355                 initializer_.mtx_.Lock();
00356             }
00357 
00359             explicit Lock(const ClassLevelLockable&)
00360             {
00361                 assert(initializer_.init_);
00362                 initializer_.mtx_.Lock();
00363             }
00364 
00366             explicit Lock(const ClassLevelLockable*)
00367             {
00368                 assert(initializer_.init_);
00369                 initializer_.mtx_.Lock();
00370             }
00371 
00373             ~Lock()
00374             {
00375                 assert(initializer_.init_);
00376                 initializer_.mtx_.Unlock();
00377             }
00378 
00379         private:
00380             Lock(const Lock&);
00381             Lock& operator=(const Lock&);
00382         };
00383 
00384         typedef volatile Host VolatileType;
00385 
00386         typedef LOKI_THREADS_LONG IntType; 
00387 
00388         LOKI_THREADS_ATOMIC_FUNCTIONS
00389         
00390     };
00391 
00392 #ifdef LOKI_PTHREAD_H 
00393     template <class Host, class MutexPolicy>
00394     pthread_mutex_t ClassLevelLockable<Host, MutexPolicy>::atomic_mutex_ = PTHREAD_MUTEX_INITIALIZER;
00395 #endif
00396 
00397     template < class Host, class MutexPolicy >
00398     typename ClassLevelLockable< Host, MutexPolicy >::Initializer 
00399     ClassLevelLockable< Host, MutexPolicy >::initializer_;
00400 
00401 #endif // #if defined(LOKI_WINDOWS_H) || defined(LOKI_PTHREAD_H) 
00402   
00403 } // namespace Loki
00404 
00405 
00406 #endif // end file guardian
00407 

Generated on Sun Feb 25 16:52:28 2007 for Loki by  doxygen 1.5.1-p1