00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifndef _TINYTHREAD_H_
00025 #define _TINYTHREAD_H_
00026
00057
00058
00059 #if !defined(_TTHREAD_PLATFORM_DEFINED_)
00060 #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__)
00061 #define _TTHREAD_WIN32_
00062 #else
00063 #define _TTHREAD_POSIX_
00064 #endif
00065 #define _TTHREAD_PLATFORM_DEFINED_
00066 #endif
00067
00068
00069 #if defined(_TTHREAD_WIN32_)
00070 #include <windows.h>
00071 #else
00072 #include <pthread.h>
00073 #include <signal.h>
00074 #include <sched.h>
00075 #include <unistd.h>
00076 #endif
00077
00078
00079 #include <ostream>
00080
00082 #define TINYTHREAD_VERSION_MAJOR 1
00083
00084 #define TINYTHREAD_VERSION_MINOR 0
00085
00086 #define TINYTHREAD_VERSION (TINYTHREAD_VERSION_MAJOR * 100 + TINYTHREAD_VERSION_MINOR)
00087
00088
00089 #if (__cplusplus > 199711L) || (defined(__STDCXX_VERSION__) && (__STDCXX_VERSION__ >= 201001L))
00090 #define _TTHREAD_CPP0X_
00091 #endif
00092
00093
00094 #if defined(_TTHREAD_CPP0X_) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__)
00095 #define _TTHREAD_CPP0X_PARTIAL_
00096 #endif
00097
00098
00099 #ifdef _TTHREAD_CPP0X_PARTIAL_
00100 #define _TTHREAD_DISABLE_ASSIGNMENT(name) \
00101 name(const name&) = delete; \
00102 name& operator=(const name&) = delete;
00103 #else
00104 #define _TTHREAD_DISABLE_ASSIGNMENT(name) \
00105 name(const name&); \
00106 name& operator=(const name&);
00107 #endif
00108
00129
00130 #if !defined(_TTHREAD_CPP0X_) && !defined(thread_local)
00131 #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__)
00132 #define thread_local __thread
00133 #else
00134 #define thread_local __declspec(thread)
00135 #endif
00136 #endif
00137
00138
00143 namespace tthread {
00144
00151 class mutex {
00152 public:
00154 mutex()
00155 #if defined(_TTHREAD_WIN32_)
00156 : mAlreadyLocked(false)
00157 #endif
00158 {
00159 #if defined(_TTHREAD_WIN32_)
00160 InitializeCriticalSection(&mHandle);
00161 #else
00162 pthread_mutex_init(&mHandle, NULL);
00163 #endif
00164 }
00165
00167 ~mutex()
00168 {
00169 #if defined(_TTHREAD_WIN32_)
00170 DeleteCriticalSection(&mHandle);
00171 #else
00172 pthread_mutex_destroy(&mHandle);
00173 #endif
00174 }
00175
00180 inline void lock()
00181 {
00182 #if defined(_TTHREAD_WIN32_)
00183 EnterCriticalSection(&mHandle);
00184 while(mAlreadyLocked) Sleep(1000);
00185 mAlreadyLocked = true;
00186 #else
00187 pthread_mutex_lock(&mHandle);
00188 #endif
00189 }
00190
00196 inline bool try_lock()
00197 {
00198 #if defined(_TTHREAD_WIN32_)
00199 bool ret = (TryEnterCriticalSection(&mHandle) ? true : false);
00200 if(ret && mAlreadyLocked)
00201 {
00202 LeaveCriticalSection(&mHandle);
00203 ret = false;
00204 }
00205 return ret;
00206 #else
00207 return (pthread_mutex_trylock(&mHandle) == 0) ? true : false;
00208 #endif
00209 }
00210
00214 inline void unlock()
00215 {
00216 #if defined(_TTHREAD_WIN32_)
00217 mAlreadyLocked = false;
00218 LeaveCriticalSection(&mHandle);
00219 #else
00220 pthread_mutex_unlock(&mHandle);
00221 #endif
00222 }
00223
00224 _TTHREAD_DISABLE_ASSIGNMENT(mutex)
00225
00226 private:
00227 #if defined(_TTHREAD_WIN32_)
00228 CRITICAL_SECTION mHandle;
00229 bool mAlreadyLocked;
00230 #else
00231 pthread_mutex_t mHandle;
00232 #endif
00233
00234 friend class condition_variable;
00235 };
00236
00243 class recursive_mutex {
00244 public:
00246 recursive_mutex()
00247 {
00248 #if defined(_TTHREAD_WIN32_)
00249 InitializeCriticalSection(&mHandle);
00250 #else
00251 pthread_mutexattr_t attr;
00252 pthread_mutexattr_init(&attr);
00253 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
00254 pthread_mutex_init(&mHandle, &attr);
00255 #endif
00256 }
00257
00259 ~recursive_mutex()
00260 {
00261 #if defined(_TTHREAD_WIN32_)
00262 DeleteCriticalSection(&mHandle);
00263 #else
00264 pthread_mutex_destroy(&mHandle);
00265 #endif
00266 }
00267
00272 inline void lock()
00273 {
00274 #if defined(_TTHREAD_WIN32_)
00275 EnterCriticalSection(&mHandle);
00276 #else
00277 pthread_mutex_lock(&mHandle);
00278 #endif
00279 }
00280
00286 inline bool try_lock()
00287 {
00288 #if defined(_TTHREAD_WIN32_)
00289 return TryEnterCriticalSection(&mHandle) ? true : false;
00290 #else
00291 return (pthread_mutex_trylock(&mHandle) == 0) ? true : false;
00292 #endif
00293 }
00294
00298 inline void unlock()
00299 {
00300 #if defined(_TTHREAD_WIN32_)
00301 LeaveCriticalSection(&mHandle);
00302 #else
00303 pthread_mutex_unlock(&mHandle);
00304 #endif
00305 }
00306
00307 _TTHREAD_DISABLE_ASSIGNMENT(recursive_mutex)
00308
00309 private:
00310 #if defined(_TTHREAD_WIN32_)
00311 CRITICAL_SECTION mHandle;
00312 #else
00313 pthread_mutex_t mHandle;
00314 #endif
00315
00316 friend class condition_variable;
00317 };
00318
00333
00334 template <class T>
00335 class lock_guard {
00336 public:
00337 typedef T mutex_type;
00338
00339 lock_guard() : mMutex(0) {}
00340
00342 explicit lock_guard(mutex_type &aMutex)
00343 {
00344 mMutex = &aMutex;
00345 mMutex->lock();
00346 }
00347
00349 ~lock_guard()
00350 {
00351 if(mMutex)
00352 mMutex->unlock();
00353 }
00354
00355 private:
00356 mutex_type * mMutex;
00357 };
00358
00384 class condition_variable {
00385 public:
00387 #if defined(_TTHREAD_WIN32_)
00388 condition_variable();
00389 #else
00390 condition_variable()
00391 {
00392 pthread_cond_init(&mHandle, NULL);
00393 }
00394 #endif
00395
00397 #if defined(_TTHREAD_WIN32_)
00398 ~condition_variable();
00399 #else
00400 ~condition_variable()
00401 {
00402 pthread_cond_destroy(&mHandle);
00403 }
00404 #endif
00405
00411 template <class _mutexT>
00412 inline void wait(_mutexT &aMutex)
00413 {
00414 #if defined(_TTHREAD_WIN32_)
00415
00416 EnterCriticalSection(&mWaitersCountLock);
00417 ++ mWaitersCount;
00418 LeaveCriticalSection(&mWaitersCountLock);
00419
00420
00421
00422 aMutex.unlock();
00423 _wait();
00424 aMutex.lock();
00425 #else
00426 pthread_cond_wait(&mHandle, &aMutex.mHandle);
00427 #endif
00428 }
00429
00435 #if defined(_TTHREAD_WIN32_)
00436 void notify_one();
00437 #else
00438 inline void notify_one()
00439 {
00440 pthread_cond_signal(&mHandle);
00441 }
00442 #endif
00443
00449 #if defined(_TTHREAD_WIN32_)
00450 void notify_all();
00451 #else
00452 inline void notify_all()
00453 {
00454 pthread_cond_broadcast(&mHandle);
00455 }
00456 #endif
00457
00458 _TTHREAD_DISABLE_ASSIGNMENT(condition_variable)
00459
00460 private:
00461 #if defined(_TTHREAD_WIN32_)
00462 void _wait();
00463 HANDLE mEvents[2];
00464 unsigned int mWaitersCount;
00465 CRITICAL_SECTION mWaitersCountLock;
00466 #else
00467 pthread_cond_t mHandle;
00468 #endif
00469 };
00470
00471
00473 class thread {
00474 public:
00475 #if defined(_TTHREAD_WIN32_)
00476 typedef HANDLE native_handle_type;
00477 #else
00478 typedef pthread_t native_handle_type;
00479 #endif
00480
00481 class id;
00482
00486 thread() : mHandle(0), mNotAThread(true)
00487 #if defined(_TTHREAD_WIN32_)
00488 , mWin32ThreadID(0)
00489 #endif
00490 {}
00491
00500 thread(void (*aFunction)(void *), void * aArg);
00501
00506 ~thread();
00507
00509 void join();
00510
00513 bool joinable() const;
00514
00516 id get_id() const;
00517
00521 inline native_handle_type native_handle()
00522 {
00523 return mHandle;
00524 }
00525
00531 static unsigned hardware_concurrency();
00532
00533 _TTHREAD_DISABLE_ASSIGNMENT(thread)
00534
00535 private:
00536 native_handle_type mHandle;
00537 mutable mutex mDataMutex;
00538 bool mNotAThread;
00539 #if defined(_TTHREAD_WIN32_)
00540 unsigned int mWin32ThreadID;
00541 #endif
00542
00543
00544 #if defined(_TTHREAD_WIN32_)
00545 static unsigned WINAPI wrapper_function(void * aArg);
00546 #else
00547 static void * wrapper_function(void * aArg);
00548 #endif
00549 };
00550
00554 class thread::id {
00555 public:
00559 id() : mId(0) {};
00560
00561 id(unsigned long int aId) : mId(aId) {};
00562
00563 id(const id& aId) : mId(aId.mId) {};
00564
00565 inline id & operator=(const id &aId)
00566 {
00567 mId = aId.mId;
00568 return *this;
00569 }
00570
00571 inline friend bool operator==(const id &aId1, const id &aId2)
00572 {
00573 return (aId1.mId == aId2.mId);
00574 }
00575
00576 inline friend bool operator!=(const id &aId1, const id &aId2)
00577 {
00578 return (aId1.mId != aId2.mId);
00579 }
00580
00581 inline friend bool operator<=(const id &aId1, const id &aId2)
00582 {
00583 return (aId1.mId <= aId2.mId);
00584 }
00585
00586 inline friend bool operator<(const id &aId1, const id &aId2)
00587 {
00588 return (aId1.mId < aId2.mId);
00589 }
00590
00591 inline friend bool operator>=(const id &aId1, const id &aId2)
00592 {
00593 return (aId1.mId >= aId2.mId);
00594 }
00595
00596 inline friend bool operator>(const id &aId1, const id &aId2)
00597 {
00598 return (aId1.mId > aId2.mId);
00599 }
00600
00601 inline friend std::ostream& operator <<(std::ostream &os, const id &obj)
00602 {
00603 os << obj.mId;
00604 return os;
00605 }
00606
00607 private:
00608 unsigned long int mId;
00609 };
00610
00611
00612
00613 typedef long long __intmax_t;
00614
00617 template <__intmax_t N, __intmax_t D = 1> class ratio {
00618 public:
00619 static double _as_double() { return double(N) / double(D); }
00620 };
00621
00624 namespace chrono {
00627 template <class _Rep, class _Period = ratio<1> > class duration {
00628 private:
00629 _Rep rep_;
00630 public:
00631 typedef _Rep rep;
00632 typedef _Period period;
00633
00635 template <class _Rep2>
00636 explicit duration(const _Rep2& r) : rep_(r) {};
00637
00639 rep count() const
00640 {
00641 return rep_;
00642 }
00643 };
00644
00645
00646 typedef duration<__intmax_t, ratio<1, 1000000000> > nanoseconds;
00647 typedef duration<__intmax_t, ratio<1, 1000000> > microseconds;
00648 typedef duration<__intmax_t, ratio<1, 1000> > milliseconds;
00649 typedef duration<__intmax_t> seconds;
00650 typedef duration<__intmax_t, ratio<60> > minutes;
00651 typedef duration<__intmax_t, ratio<3600> > hours;
00652 }
00653
00656 namespace this_thread {
00658 thread::id get_id();
00659
00663 inline void yield()
00664 {
00665 #if defined(_TTHREAD_WIN32_)
00666 Sleep(0);
00667 #else
00668 sched_yield();
00669 #endif
00670 }
00671
00681 template <class _Rep, class _Period> void sleep_for(const chrono::duration<_Rep, _Period>& aTime)
00682 {
00683 #if defined(_TTHREAD_WIN32_)
00684 Sleep(int(double(aTime.count()) * (1000.0 * _Period::_as_double()) + 0.5));
00685 #else
00686 usleep(int(double(aTime.count()) * (1000000.0 * _Period::_as_double()) + 0.5));
00687 #endif
00688 }
00689 }
00690
00691 }
00692
00693
00694 #undef _TTHREAD_DISABLE_ASSIGNMENT
00695
00696 #endif // _TINYTHREAD_H_