00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00037
00038
00039 #ifndef OPENIMAGEIO_THREAD_H
00040 #define OPENIMAGEIO_THREAD_H
00041
00042
00043
00044
00045 #ifdef _WIN32
00046 # define NOMINMAX
00047 #endif
00048
00049 #include <boost/thread.hpp>
00050 #include <boost/thread/tss.hpp>
00051 #include <boost/version.hpp>
00052 #if (BOOST_VERSION == 103500)
00053 # include <boost/thread/shared_mutex.hpp>
00054 #endif
00055 #if (BOOST_VERSION < 103500)
00056 # include <pthread.h>
00057 #endif
00058
00059 #ifndef USE_TBB
00060 # if defined(_WIN32) && (_MSV_VER >= 1500)
00061 # define USE_TBB 0
00062 # else
00063 # define USE_TBB 1
00064 # endif
00065 #endif
00066
00067
00068
00069 #if USE_TBB
00070 # include <tbb/atomic.h>
00071 using tbb::atomic;
00072 # include <tbb/spin_mutex.h>
00073 #else
00074 # if defined(__GNUC__) && defined(_GLIBCXX_ATOMIC_BUILTINS)
00075
00076 # elif defined(__APPLE__)
00077 # include <libkern/OSAtomic.h>
00078 # elif defined(_WIN32)
00079 # include <windows.h>
00080 # include <winbase.h>
00081 # else
00082 # error "Ouch, no atomics!"
00083 # endif
00084 #endif
00085
00086 #ifdef __APPLE__
00087 # include <libkern/OSAtomic.h>
00088 #endif
00089
00090
00091 #ifdef OPENIMAGEIO_NAMESPACE
00092 namespace OPENIMAGEIO_NAMESPACE {
00093 #endif
00094
00095
00098 class null_mutex {
00099 public:
00100 null_mutex () { }
00101 ~null_mutex () { }
00102 void lock () { }
00103 void unlock () { }
00104 void lock_shared () { }
00105 void unlock_shared () { }
00106 };
00107
00110 template<typename T>
00111 class null_lock {
00112 public:
00113 null_lock (T &m) { }
00114 };
00115
00116
00117
00118
00119 template<typename T>
00120 class null_thread_specific_ptr {
00121 public:
00122 typedef void (*destructor_t)(T *);
00123 null_thread_specific_ptr (destructor_t dest=NULL)
00124 : m_ptr(NULL), m_dest(dest) { }
00125 ~null_thread_specific_ptr () { reset (NULL); }
00126 T * get () { return m_ptr; }
00127 void reset (T *newptr=NULL) {
00128 if (m_ptr) {
00129 if (m_dest)
00130 (*m_dest) (m_ptr);
00131 else
00132 delete m_ptr;
00133 }
00134 m_ptr = newptr;
00135 }
00136 private:
00137 T *m_ptr;
00138 destructor_t m_dest;
00139 };
00140
00141
00142 #ifdef NOTHREADS
00143
00144
00145
00146
00147
00148
00149 template<typename T>
00150 class thread_specific_ptr {
00151 public:
00152 typedef void (*destructor_t)(T *);
00153 thread_specific_ptr (destructor_t dest=NULL)
00154 : m_ptr(NULL), m_dest(dest) { }
00155 ~thread_specific_ptr () { reset (NULL); }
00156 T * get () { return m_ptr; }
00157 void reset (T *newptr=NULL) {
00158 if (m_ptr) {
00159 if (m_dest)
00160 (*m_dest) (m_ptr);
00161 else
00162 delete m_ptr;
00163 }
00164 m_ptr = newptr;
00165 }
00166 private:
00167 T *m_ptr;
00168 destructor_t m_dest;
00169 };
00170
00171
00172 typedef null_mutex mutex;
00173 typedef null_mutex recursive_mutex;
00174 typedef null_mutex shared_mutex;
00175 typedef null_lock<mutex> lock_guard;
00176 typedef null_lock<recursive_mutex> recursive_lock_guard;
00177 typedef null_lock<shared_mutex> shared_lock;
00178 typedef null_lock<shared_mutex> unique_lock;
00179
00180
00181 #elif (BOOST_VERSION >= 103500)
00182
00183
00184
00185 typedef boost::mutex mutex;
00186 typedef boost::recursive_mutex recursive_mutex;
00187 typedef boost::shared_mutex shared_mutex;
00188 typedef boost::lock_guard< boost::mutex > lock_guard;
00189 typedef boost::lock_guard< boost::recursive_mutex > recursive_lock_guard;
00190 typedef boost::shared_lock< boost::shared_mutex > shared_lock;
00191 typedef boost::unique_lock< boost::shared_mutex > unique_lock;
00192 using boost::thread_specific_ptr;
00193
00194 #else
00195
00196
00197
00198
00199
00200
00201
00202 typedef boost::mutex mutex;
00203 typedef boost::recursive_mutex recursive_mutex;
00204 typedef boost::mutex::scoped_lock lock_guard;
00205 typedef boost::recursive_mutex::scoped_lock recursive_lock_guard;
00206 using boost::thread_specific_ptr;
00207
00208
00209 class shared_mutex {
00210 public:
00211 shared_mutex () { pthread_rwlock_init (&m_rwlock, NULL); }
00212 ~shared_mutex () { pthread_rwlock_destroy (&m_rwlock); }
00213 void lock () { pthread_rwlock_wrlock (&m_rwlock); }
00214 void unlock () { pthread_rwlock_unlock (&m_rwlock); }
00215 void lock_shared () { pthread_rwlock_rdlock (&m_rwlock); }
00216 void unlock_shared () { pthread_rwlock_unlock (&m_rwlock); }
00217 private:
00218 pthread_rwlock_t m_rwlock;
00219 };
00220
00221 class shared_lock {
00222 public:
00223 shared_lock (shared_mutex &m) : m_mutex(m) { m_mutex.lock_shared (); }
00224 ~shared_lock () { m_mutex.unlock_shared (); }
00225 private:
00226 shared_mutex &m_mutex;
00227 };
00228
00229 class unique_lock {
00230 public:
00231 unique_lock (shared_mutex &m) : m_mutex(m) { m_mutex.lock (); }
00232 ~unique_lock () { m_mutex.unlock (); }
00233 private:
00234 shared_mutex &m_mutex;
00235 };
00236
00237 #endif
00238
00239
00240
00241 #if (! USE_TBB)
00242
00243
00244
00245
00246
00247
00250 inline int
00251 atomic_exchange_and_add (volatile int *at, int x)
00252 {
00253 #if defined(__GNUC__) && defined(_GLIBCXX_ATOMIC_BUILTINS)
00254 return __sync_fetch_and_add ((int *)at, x);
00255 #elif defined(__APPLE__)
00256
00257 return OSAtomicAdd32Barrier (x, at) - x;
00258 #elif defined(_WIN32)
00259
00260 return InterlockedExchangeAdd ((volatile LONG *)at, x);
00261 #endif
00262 }
00263
00264
00265
00266 inline long long
00267 atomic_exchange_and_add (volatile long long *at, long long x)
00268 {
00269 #if defined(__GNUC__) && defined(_GLIBCXX_ATOMIC_BUILTINS)
00270 return __sync_fetch_and_add (at, x);
00271 #elif defined(__APPLE__)
00272
00273 return OSAtomicAdd64Barrier (x, at) - x;
00274 #elif defined(_WIN32)
00275
00276 return InterlockedExchangeAdd64 ((volatile LONGLONG *)at, x);
00277 #endif
00278 }
00279
00280
00281
00288 inline bool
00289 atomic_compare_and_exchange (volatile int *at, int compareval, int newval)
00290 {
00291 #if defined(__GNUC__) && defined(_GLIBCXX_ATOMIC_BUILTINS)
00292 return __sync_bool_compare_and_swap (at, compareval, newval);
00293 #elif defined(__APPLE__)
00294 return OSAtomicCompareAndSwap32Barrier (compareval, newval, at);
00295 #elif defined(_WIN32)
00296 return (InterlockedCompareExchange ((volatile LONG *)at, newval, compareval) == compareval);
00297 #endif
00298 }
00299
00300
00301
00302 inline bool
00303 atomic_compare_and_exchange (volatile long long *at, long long compareval, long long newval)
00304 {
00305 #if defined(__GNUC__) && defined(_GLIBCXX_ATOMIC_BUILTINS)
00306 return __sync_bool_compare_and_swap (at, compareval, newval);
00307 #elif defined(__APPLE__)
00308 return OSAtomicCompareAndSwap64Barrier (compareval, newval, at);
00309 #elif defined(_WIN32)
00310 return (InterlockedCompareExchange64 ((volatile LONGLONG *)at, newval, compareval) == compareval);
00311 #endif
00312 }
00313
00314
00315
00318 template<class T>
00319 class atomic {
00320 public:
00323 atomic (T val=0) : m_val(val) { }
00324
00325 ~atomic () { }
00326
00329 T operator() () const { return atomic_exchange_and_add (&m_val, 0); }
00330
00333 operator T() const { return atomic_exchange_and_add (&m_val, 0); }
00334
00337 T operator= (T x) {
00338
00339 while (1) {
00340 T result = m_val;
00341 if (atomic_compare_and_exchange (&m_val, result, x))
00342 break;
00343 }
00344 return x;
00345 }
00346
00349 T operator++ () { return atomic_exchange_and_add (&m_val, 1) + 1; }
00350
00353 T operator++ (int) { return atomic_exchange_and_add (&m_val, 1); }
00354
00357 T operator-- () { return atomic_exchange_and_add (&m_val, -1) - 1; }
00358
00361 T operator-- (int) { return atomic_exchange_and_add (&m_val, -1); }
00362
00365 T operator+= (T x) { return atomic_exchange_and_add (&m_val, x) + x; }
00366
00369 T operator-= (T x) { return atomic_exchange_and_add (&m_val, -x) - x; }
00370
00371 bool bool_compare_and_swap (T compareval, T newval) {
00372 return atomic_compare_and_exchange (&m_val, compareval, newval);
00373 }
00374
00375 T operator= (const atomic &x) {
00376 T r = x();
00377 *this = r;
00378 return r;
00379 }
00380
00381 private:
00382 volatile mutable T m_val;
00383
00384
00385 atomic (atomic const &);
00386 };
00387
00388
00389 #endif
00390
00391
00392 #ifdef NOTHREADS
00393
00394 typedef int atomic_int;
00395 typedef long long atomic_ll;
00396
00397 #else
00398
00399 typedef atomic<int> atomic_int;
00400 typedef atomic<long long> atomic_ll;
00401
00402 #endif
00403
00404
00405
00406 #ifdef NOTHREADS
00407
00408 typedef null_mutex spin_mutex;
00409 typedef null_lock<spin_mutex> spin_lock;
00410
00411 #elif defined(USE_TBB)
00412
00413
00414 typedef tbb::spin_mutex spin_mutex;
00415 typedef tbb::spin_mutex::scoped_lock spin_lock;
00416
00417
00418 #else
00419
00420
00421
00422
00423
00444 class spin_mutex {
00445 public:
00448 spin_mutex (void) { m_locked = 0; }
00449
00450 ~spin_mutex (void) { }
00451
00454 spin_mutex (const spin_mutex &) { m_locked = 0; }
00455
00458 const spin_mutex& operator= (const spin_mutex&) { return *this; }
00459
00462 void lock () {
00463 #if defined(__APPLE__)
00464
00465 OSSpinLockLock ((OSSpinLock *)&m_locked);
00466 #else
00467 while (! try_lock())
00468 ;
00469 #endif
00470 }
00471
00474 void unlock () {
00475 #if defined(__APPLE__)
00476 OSSpinLockUnlock ((OSSpinLock *)&m_locked);
00477 #else
00478 m_locked = 0;
00479 #endif
00480 }
00481
00484 bool try_lock () {
00485 #if defined(__APPLE__)
00486 return OSSpinLockTry ((OSSpinLock *)&m_locked);
00487 #else
00488 # ifdef USE_TBB
00489
00490 return m_locked.compare_and_swap (0, 1) == 0;
00491 # else
00492
00493 return m_locked.bool_compare_and_swap (0, 1);
00494 # endif
00495 #endif
00496 }
00497
00500 class lock_guard {
00501 public:
00502 lock_guard (spin_mutex &fm) : m_fm(fm) { m_fm.lock(); }
00503 ~lock_guard () { m_fm.unlock(); }
00504 private:
00505 spin_mutex & m_fm;
00506 };
00507
00508 private:
00509 atomic_int m_locked;
00510 };
00511
00512
00513 typedef spin_mutex::lock_guard spin_lock;
00514
00515 #endif
00516
00517
00518
00519 #ifdef OPENIMAGEIO_NAMESPACE
00520 };
00521 using namespace OPENIMAGEIO_NAMESPACE;
00522 #endif
00523
00524 #endif // OPENIMAGEIO_THREAD_H