00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00015 #ifndef LOKI_THREADS_INC_
00016 #define LOKI_THREADS_INC_
00017
00018
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
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 }
00404
00405
00406 #endif // end file guardian
00407