TinyThread++ 1.1
tinythread.h
Go to the documentation of this file.
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_