TinyThread++ 1.1
|
00001 /* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- 00002 Copyright (c) 2010-2012 Marcus Geelnard 00003 00004 This software is provided 'as-is', without any express or implied 00005 warranty. In no event will the authors be held liable for any damages 00006 arising from the use of this software. 00007 00008 Permission is granted to anyone to use this software for any purpose, 00009 including commercial applications, and to alter it and redistribute it 00010 freely, subject to the following restrictions: 00011 00012 1. The origin of this software must not be misrepresented; you must not 00013 claim that you wrote the original software. If you use this software 00014 in a product, an acknowledgment in the product documentation would be 00015 appreciated but is not required. 00016 00017 2. Altered source versions must be plainly marked as such, and must not be 00018 misrepresented as being the original software. 00019 00020 3. This notice may not be removed or altered from any source 00021 distribution. 00022 */ 00023 00024 #ifndef _TINYTHREAD_H_ 00025 #define _TINYTHREAD_H_ 00026 00057 00058 // Which platform are we on? 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 // Platform specific includes 00069 #if defined(_TTHREAD_WIN32_) 00070 #ifndef WIN32_LEAN_AND_MEAN 00071 #define WIN32_LEAN_AND_MEAN 00072 #define __UNDEF_LEAN_AND_MEAN 00073 #endif 00074 #include <windows.h> 00075 #ifdef __UNDEF_LEAN_AND_MEAN 00076 #undef WIN32_LEAN_AND_MEAN 00077 #undef __UNDEF_LEAN_AND_MEAN 00078 #endif 00079 #else 00080 #include <pthread.h> 00081 #include <signal.h> 00082 #include <sched.h> 00083 #include <unistd.h> 00084 #endif 00085 00086 // Generic includes 00087 #include <ostream> 00088 00090 #define TINYTHREAD_VERSION_MAJOR 1 00091 00092 #define TINYTHREAD_VERSION_MINOR 1 00093 00094 #define TINYTHREAD_VERSION (TINYTHREAD_VERSION_MAJOR * 100 + TINYTHREAD_VERSION_MINOR) 00095 00096 // Do we have a fully featured C++11 compiler? 00097 #if (__cplusplus > 199711L) || (defined(__STDCXX_VERSION__) && (__STDCXX_VERSION__ >= 201001L)) 00098 #define _TTHREAD_CPP11_ 00099 #endif 00100 00101 // ...at least partial C++11? 00102 #if defined(_TTHREAD_CPP11_) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__) 00103 #define _TTHREAD_CPP11_PARTIAL_ 00104 #endif 00105 00106 // Macro for disabling assignments of objects. 00107 #ifdef _TTHREAD_CPP11_PARTIAL_ 00108 #define _TTHREAD_DISABLE_ASSIGNMENT(name) \ 00109 name(const name&) = delete; \ 00110 name& operator=(const name&) = delete; 00111 #else 00112 #define _TTHREAD_DISABLE_ASSIGNMENT(name) \ 00113 name(const name&); \ 00114 name& operator=(const name&); 00115 #endif 00116 00137 00138 #if !defined(_TTHREAD_CPP11_) && !defined(thread_local) 00139 #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) 00140 #define thread_local __thread 00141 #else 00142 #define thread_local __declspec(thread) 00143 #endif 00144 #endif 00145 00146 00151 namespace tthread { 00152 00159 class mutex { 00160 public: 00162 mutex() 00163 #if defined(_TTHREAD_WIN32_) 00164 : mAlreadyLocked(false) 00165 #endif 00166 { 00167 #if defined(_TTHREAD_WIN32_) 00168 InitializeCriticalSection(&mHandle); 00169 #else 00170 pthread_mutex_init(&mHandle, NULL); 00171 #endif 00172 } 00173 00175 ~mutex() 00176 { 00177 #if defined(_TTHREAD_WIN32_) 00178 DeleteCriticalSection(&mHandle); 00179 #else 00180 pthread_mutex_destroy(&mHandle); 00181 #endif 00182 } 00183 00188 inline void lock() 00189 { 00190 #if defined(_TTHREAD_WIN32_) 00191 EnterCriticalSection(&mHandle); 00192 while(mAlreadyLocked) Sleep(1000); // Simulate deadlock... 00193 mAlreadyLocked = true; 00194 #else 00195 pthread_mutex_lock(&mHandle); 00196 #endif 00197 } 00198 00204 inline bool try_lock() 00205 { 00206 #if defined(_TTHREAD_WIN32_) 00207 bool ret = (TryEnterCriticalSection(&mHandle) ? true : false); 00208 if(ret && mAlreadyLocked) 00209 { 00210 LeaveCriticalSection(&mHandle); 00211 ret = false; 00212 } 00213 return ret; 00214 #else 00215 return (pthread_mutex_trylock(&mHandle) == 0) ? true : false; 00216 #endif 00217 } 00218 00222 inline void unlock() 00223 { 00224 #if defined(_TTHREAD_WIN32_) 00225 mAlreadyLocked = false; 00226 LeaveCriticalSection(&mHandle); 00227 #else 00228 pthread_mutex_unlock(&mHandle); 00229 #endif 00230 } 00231 00232 _TTHREAD_DISABLE_ASSIGNMENT(mutex) 00233 00234 private: 00235 #if defined(_TTHREAD_WIN32_) 00236 CRITICAL_SECTION mHandle; 00237 bool mAlreadyLocked; 00238 #else 00239 pthread_mutex_t mHandle; 00240 #endif 00241 00242 friend class condition_variable; 00243 }; 00244 00251 class recursive_mutex { 00252 public: 00254 recursive_mutex() 00255 { 00256 #if defined(_TTHREAD_WIN32_) 00257 InitializeCriticalSection(&mHandle); 00258 #else 00259 pthread_mutexattr_t attr; 00260 pthread_mutexattr_init(&attr); 00261 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 00262 pthread_mutex_init(&mHandle, &attr); 00263 #endif 00264 } 00265 00267 ~recursive_mutex() 00268 { 00269 #if defined(_TTHREAD_WIN32_) 00270 DeleteCriticalSection(&mHandle); 00271 #else 00272 pthread_mutex_destroy(&mHandle); 00273 #endif 00274 } 00275 00280 inline void lock() 00281 { 00282 #if defined(_TTHREAD_WIN32_) 00283 EnterCriticalSection(&mHandle); 00284 #else 00285 pthread_mutex_lock(&mHandle); 00286 #endif 00287 } 00288 00294 inline bool try_lock() 00295 { 00296 #if defined(_TTHREAD_WIN32_) 00297 return TryEnterCriticalSection(&mHandle) ? true : false; 00298 #else 00299 return (pthread_mutex_trylock(&mHandle) == 0) ? true : false; 00300 #endif 00301 } 00302 00306 inline void unlock() 00307 { 00308 #if defined(_TTHREAD_WIN32_) 00309 LeaveCriticalSection(&mHandle); 00310 #else 00311 pthread_mutex_unlock(&mHandle); 00312 #endif 00313 } 00314 00315 _TTHREAD_DISABLE_ASSIGNMENT(recursive_mutex) 00316 00317 private: 00318 #if defined(_TTHREAD_WIN32_) 00319 CRITICAL_SECTION mHandle; 00320 #else 00321 pthread_mutex_t mHandle; 00322 #endif 00323 00324 friend class condition_variable; 00325 }; 00326 00341 00342 template <class T> 00343 class lock_guard { 00344 public: 00345 typedef T mutex_type; 00346 00347 lock_guard() : mMutex(0) {} 00348 00350 explicit lock_guard(mutex_type &aMutex) 00351 { 00352 mMutex = &aMutex; 00353 mMutex->lock(); 00354 } 00355 00357 ~lock_guard() 00358 { 00359 if(mMutex) 00360 mMutex->unlock(); 00361 } 00362 00363 private: 00364 mutex_type * mMutex; 00365 }; 00366 00392 class condition_variable { 00393 public: 00395 #if defined(_TTHREAD_WIN32_) 00396 condition_variable(); 00397 #else 00398 condition_variable() 00399 { 00400 pthread_cond_init(&mHandle, NULL); 00401 } 00402 #endif 00403 00405 #if defined(_TTHREAD_WIN32_) 00406 ~condition_variable(); 00407 #else 00408 ~condition_variable() 00409 { 00410 pthread_cond_destroy(&mHandle); 00411 } 00412 #endif 00413 00419 template <class _mutexT> 00420 inline void wait(_mutexT &aMutex) 00421 { 00422 #if defined(_TTHREAD_WIN32_) 00423 // Increment number of waiters 00424 EnterCriticalSection(&mWaitersCountLock); 00425 ++ mWaitersCount; 00426 LeaveCriticalSection(&mWaitersCountLock); 00427 00428 // Release the mutex while waiting for the condition (will decrease 00429 // the number of waiters when done)... 00430 aMutex.unlock(); 00431 _wait(); 00432 aMutex.lock(); 00433 #else 00434 pthread_cond_wait(&mHandle, &aMutex.mHandle); 00435 #endif 00436 } 00437 00443 #if defined(_TTHREAD_WIN32_) 00444 void notify_one(); 00445 #else 00446 inline void notify_one() 00447 { 00448 pthread_cond_signal(&mHandle); 00449 } 00450 #endif 00451 00457 #if defined(_TTHREAD_WIN32_) 00458 void notify_all(); 00459 #else 00460 inline void notify_all() 00461 { 00462 pthread_cond_broadcast(&mHandle); 00463 } 00464 #endif 00465 00466 _TTHREAD_DISABLE_ASSIGNMENT(condition_variable) 00467 00468 private: 00469 #if defined(_TTHREAD_WIN32_) 00470 void _wait(); 00471 HANDLE mEvents[2]; 00472 unsigned int mWaitersCount; 00473 CRITICAL_SECTION mWaitersCountLock; 00474 #else 00475 pthread_cond_t mHandle; 00476 #endif 00477 }; 00478 00479 00481 class thread { 00482 public: 00483 #if defined(_TTHREAD_WIN32_) 00484 typedef HANDLE native_handle_type; 00485 #else 00486 typedef pthread_t native_handle_type; 00487 #endif 00488 00489 class id; 00490 00494 thread() : mHandle(0), mNotAThread(true) 00495 #if defined(_TTHREAD_WIN32_) 00496 , mWin32ThreadID(0) 00497 #endif 00498 {} 00499 00508 thread(void (*aFunction)(void *), void * aArg); 00509 00514 ~thread(); 00515 00520 void join(); 00521 00524 bool joinable() const; 00525 00531 void detach(); 00532 00534 id get_id() const; 00535 00539 inline native_handle_type native_handle() 00540 { 00541 return mHandle; 00542 } 00543 00549 static unsigned hardware_concurrency(); 00550 00551 _TTHREAD_DISABLE_ASSIGNMENT(thread) 00552 00553 private: 00554 native_handle_type mHandle; 00555 mutable mutex mDataMutex; 00556 bool mNotAThread; 00557 #if defined(_TTHREAD_WIN32_) 00558 unsigned int mWin32ThreadID; 00559 #endif 00560 00561 // This is the internal thread wrapper function. 00562 #if defined(_TTHREAD_WIN32_) 00563 static unsigned WINAPI wrapper_function(void * aArg); 00564 #else 00565 static void * wrapper_function(void * aArg); 00566 #endif 00567 }; 00568 00572 class thread::id { 00573 public: 00577 id() : mId(0) {}; 00578 00579 id(unsigned long int aId) : mId(aId) {}; 00580 00581 id(const id& aId) : mId(aId.mId) {}; 00582 00583 inline id & operator=(const id &aId) 00584 { 00585 mId = aId.mId; 00586 return *this; 00587 } 00588 00589 inline friend bool operator==(const id &aId1, const id &aId2) 00590 { 00591 return (aId1.mId == aId2.mId); 00592 } 00593 00594 inline friend bool operator!=(const id &aId1, const id &aId2) 00595 { 00596 return (aId1.mId != aId2.mId); 00597 } 00598 00599 inline friend bool operator<=(const id &aId1, const id &aId2) 00600 { 00601 return (aId1.mId <= aId2.mId); 00602 } 00603 00604 inline friend bool operator<(const id &aId1, const id &aId2) 00605 { 00606 return (aId1.mId < aId2.mId); 00607 } 00608 00609 inline friend bool operator>=(const id &aId1, const id &aId2) 00610 { 00611 return (aId1.mId >= aId2.mId); 00612 } 00613 00614 inline friend bool operator>(const id &aId1, const id &aId2) 00615 { 00616 return (aId1.mId > aId2.mId); 00617 } 00618 00619 inline friend std::ostream& operator <<(std::ostream &os, const id &obj) 00620 { 00621 os << obj.mId; 00622 return os; 00623 } 00624 00625 private: 00626 unsigned long int mId; 00627 }; 00628 00629 00630 // Related to <ratio> - minimal to be able to support chrono. 00631 typedef long long __intmax_t; 00632 00635 template <__intmax_t N, __intmax_t D = 1> class ratio { 00636 public: 00637 static double _as_double() { return double(N) / double(D); } 00638 }; 00639 00642 namespace chrono { 00645 template <class _Rep, class _Period = ratio<1> > class duration { 00646 private: 00647 _Rep rep_; 00648 public: 00649 typedef _Rep rep; 00650 typedef _Period period; 00651 00653 template <class _Rep2> 00654 explicit duration(const _Rep2& r) : rep_(r) {}; 00655 00657 rep count() const 00658 { 00659 return rep_; 00660 } 00661 }; 00662 00663 // Standard duration types. 00664 typedef duration<__intmax_t, ratio<1, 1000000000> > nanoseconds; 00665 typedef duration<__intmax_t, ratio<1, 1000000> > microseconds; 00666 typedef duration<__intmax_t, ratio<1, 1000> > milliseconds; 00667 typedef duration<__intmax_t> seconds; 00668 typedef duration<__intmax_t, ratio<60> > minutes; 00669 typedef duration<__intmax_t, ratio<3600> > hours; 00670 } 00671 00674 namespace this_thread { 00676 thread::id get_id(); 00677 00681 inline void yield() 00682 { 00683 #if defined(_TTHREAD_WIN32_) 00684 Sleep(0); 00685 #else 00686 sched_yield(); 00687 #endif 00688 } 00689 00699 template <class _Rep, class _Period> void sleep_for(const chrono::duration<_Rep, _Period>& aTime) 00700 { 00701 #if defined(_TTHREAD_WIN32_) 00702 Sleep(int(double(aTime.count()) * (1000.0 * _Period::_as_double()) + 0.5)); 00703 #else 00704 usleep(int(double(aTime.count()) * (1000000.0 * _Period::_as_double()) + 0.5)); 00705 #endif 00706 } 00707 } 00708 00709 } 00710 00711 // Define/macro cleanup 00712 #undef _TTHREAD_DISABLE_ASSIGNMENT 00713 00714 #endif // _TINYTHREAD_H_