TinyThread++: tinythread.h Source File

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

# tinythread.h

Go to the documentation of this file.

    00001 /*
    00002 Copyright (c) 2010 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   #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 // Generic includes
    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 // Do we have a fully featured C++0x compiler?
    00089 #if (__cplusplus > 199711L) || (defined(__STDCXX_VERSION__) && (__STDCXX_VERSION__ >= 201001L))
    00090   #define _TTHREAD_CPP0X_
    00091 #endif
    00092
    00093 // ...at least partial C++0x?
    00094 #if defined(_TTHREAD_CPP0X_) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__)
    00095   #define _TTHREAD_CPP0X_PARTIAL_
    00096 #endif
    00097
    00098 // Macro for disabling assignments of objects.
    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); // Simulate deadlock...
    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       // Increment number of waiters
    00416       EnterCriticalSection(&mWaitersCountLock);
    00417       ++ mWaitersCount;
    00418       LeaveCriticalSection(&mWaitersCountLock);
    00419
    00420       // Release the mutex while waiting for the condition (will decrease
    00421       // the number of waiters when done)...
    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     // This is the internal thread wrapper function.
    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 // Related to <ratio> - minimal to be able to support chrono.
    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   // Standard duration types.
    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 // Define/macro cleanup
    00694 #undef _TTHREAD_DISABLE_ASSIGNMENT
    00695
    00696 #endif // _TINYTHREAD_H_