tinythread.h
上传用户:sunlush021
上传日期:2022-06-22
资源大小:90k
文件大小:12k
源码类别:

操作系统开发

开发平台:

C/C++

  1. /*
  2. Copyright (c) 2010 Marcus Geelnard
  3. This software is provided 'as-is', without any express or implied
  4. warranty. In no event will the authors be held liable for any damages
  5. arising from the use of this software.
  6. Permission is granted to anyone to use this software for any purpose,
  7. including commercial applications, and to alter it and redistribute it
  8. freely, subject to the following restrictions:
  9.     1. The origin of this software must not be misrepresented; you must not
  10.     claim that you wrote the original software. If you use this software
  11.     in a product, an acknowledgment in the product documentation would be
  12.     appreciated but is not required.
  13.     2. Altered source versions must be plainly marked as such, and must not be
  14.     misrepresented as being the original software.
  15.     3. This notice may not be removed or altered from any source
  16.     distribution.
  17. */
  18. #ifndef _TINYTHREAD_H_
  19. #define _TINYTHREAD_H_
  20. /// @file
  21. /// @mainpage TinyThread++ API Reference
  22. ///
  23. /// @section intro_sec Introduction
  24. /// TinyThread++ is a minimal, portable implementation of basic threading
  25. /// classes for C++.
  26. ///
  27. /// They closely mimic the functionality and naming of the C++0x standard, and
  28. /// should be easily replaceable with the corresponding std:: variants.
  29. ///
  30. /// @section port_sec Portability
  31. /// The Win32 variant uses the native Win32 API for implementing the thread
  32. /// classes, while for other systems, the POSIX threads API (pthread) is used.
  33. ///
  34. /// @section class_sec Classes
  35. /// There are five classes that are implemented: tthread::thread, tthread::id,
  36. /// tthread::mutex, tthread::lock_guard and tthread::condition_variable.
  37. ///
  38. /// @section misc_sec Miscellaneous
  39. /// The following keywords are available: #thread_local.
  40. ///
  41. /// The following functions are available: tthread::number_of_processors().
  42. // Which platform are we on?
  43. #if !defined(_TTHREAD_PLATFORM_DEFINED_)
  44.   #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__)
  45.     #define _TTHREAD_WIN32_
  46.   #else
  47.     #define _TTHREAD_POSIX_
  48.   #endif
  49.   #define _TTHREAD_PLATFORM_DEFINED_
  50. #endif
  51. // Platform specific includes
  52. #if defined(_TTHREAD_WIN32_)
  53.   #include <windows.h>
  54. #else
  55.   #include <pthread.h>
  56.   #include <signal.h>
  57. #endif
  58. // Generic includes
  59. #include <ostream>
  60. /// TinyThread++ version (major number).
  61. #define TINYTHREAD_VERSION_MAJOR 0
  62. /// TinyThread++ version (minor number).
  63. #define TINYTHREAD_VERSION_MINOR 6
  64. /// TinyThread++ version (full version).
  65. #define TINYTHREAD_VERSION (TINYTHREAD_VERSION_MAJOR * 100 + TINYTHREAD_VERSION_MINOR)
  66. /// @def thread_local
  67. /// Thread local storage keyword.
  68. /// A variable that is declared with the c thread_local keyword makes the
  69. /// value of the variable local to each thread (known as thread-local storage,
  70. /// or TLS). Example usage:
  71. /// @code
  72. /// // This variable is local to each thread.
  73. /// thread_local int variable;
  74. /// @endcode
  75. /// @note The c thread_local keyword is a macro that maps to the corresponding
  76. /// compiler directive (e.g. c __declspec(thread)). While the C++0x standard
  77. /// allows for non-trivial types (e.g. classes with constructors and
  78. /// destructors) to be declared with the c thread_local keyword, most pre-C++0x
  79. /// compilers only allow for trivial types (e.g. c int). So, to guarantee
  80. /// portable code, only use trivial types for thread local storage.
  81. /// @note This directive is currently not supported on Mac OS X (it will give
  82. /// a compiler error), since compile-time TLS is not supported in the Mac OS X
  83. /// executable format.
  84. /// @hideinitializer
  85. #if (__cplusplus <= 199711L) && !defined(thread_local)
  86.  #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__)
  87.   #define thread_local __thread
  88.  #else
  89.   #define thread_local __declspec(thread)
  90.  #endif
  91. #endif
  92. /// Main name space for TinyThread++.
  93. /// This namespace is more or less equivalent to the c std namespace for the
  94. /// C++0x thread classes. For instance, the tthread::mutex class corresponds to
  95. /// the std::mutex class.
  96. namespace tthread {
  97. /// Mutex class.
  98. /// This is a mutual exclusion object for synchronizing access to shared
  99. /// memory areas for several threads.
  100. /// @note Unlike the C++0x c mutex class (which is strictly non-recursive),
  101. /// this class may or may not be recursive, depending on the underlying system
  102. /// implementation.
  103. class mutex {
  104.   public:
  105.     /// Constructor.
  106.     mutex()
  107.     {
  108. #if defined(_TTHREAD_WIN32_)
  109.       InitializeCriticalSection(&mHandle);
  110. #else
  111.       pthread_mutex_init(&mHandle, NULL);
  112. #endif
  113.     }
  114.     /// Destructor.
  115.     ~mutex()
  116.     {
  117. #if defined(_TTHREAD_WIN32_)
  118.       DeleteCriticalSection(&mHandle);
  119. #else
  120.       pthread_mutex_destroy(&mHandle);
  121. #endif
  122.     }
  123.     /// Lock the mutex.
  124.     /// The method will block the calling thread until a lock on the mutex can
  125.     /// be obtained. The mutex remains locked until c unlock() is called.
  126.     /// @see lock_guard
  127.     inline void lock()
  128.     {
  129. #if defined(_TTHREAD_WIN32_)
  130.       EnterCriticalSection(&mHandle);
  131. #else
  132.       pthread_mutex_lock(&mHandle);
  133. #endif
  134.     }
  135.     /// Try to lock the mutex.
  136.     /// The method will try to lock the mutex. If it fails, the function will
  137.     /// return immediately (non-blocking).
  138.     /// @return c true if the lock was acquired, or c false if the lock could
  139.     /// not be acquired.
  140.     inline bool try_lock()
  141.     {
  142. #if defined(_TTHREAD_WIN32_)
  143.       return TryEnterCriticalSection(&mHandle) ? true : false;
  144. #else
  145.       return (pthread_mutex_trylock(&mHandle) == 0) ? true : false;
  146. #endif
  147.     }
  148.     /// Unlock the mutex.
  149.     /// If any threads are waiting for the lock on this mutex, one of them will
  150.     /// be unblocked.
  151.     inline void unlock()
  152.     {
  153. #if defined(_TTHREAD_WIN32_)
  154.       LeaveCriticalSection(&mHandle);
  155. #else
  156.       pthread_mutex_unlock(&mHandle);
  157. #endif
  158.     }
  159.   private:
  160. #if defined(_TTHREAD_WIN32_)
  161.     CRITICAL_SECTION mHandle;
  162. #else
  163.     pthread_mutex_t mHandle;
  164. #endif
  165.     friend class condition_variable;
  166. };
  167. /// Lock guard class.
  168. /// The constructor locks the mutex, and the destructor unlocks the mutex, so
  169. /// the mutex will automatically be unlocked when the lock guard goes out of
  170. /// scope. Example usage:
  171. /// @code
  172. /// mutex m;
  173. /// int counter;
  174. ///
  175. /// void increment()
  176. /// {
  177. ///   lock_guard<mutex> guard(m);
  178. ///   ++ counter;
  179. /// }
  180. /// @endcode
  181. template <class T>
  182. class lock_guard {
  183.   public:
  184.     typedef T mutex_type;
  185.     lock_guard() : mMutex(0) {}
  186.     /// The constructor locks the mutex.
  187.     explicit lock_guard(mutex_type &aMutex)
  188.     {
  189.       mMutex = &aMutex;
  190.       mMutex->lock();
  191.     }
  192.     /// The destructor unlocks the mutex.
  193.     ~lock_guard()
  194.     {
  195.       if(mMutex)
  196.         mMutex->unlock();
  197.     }
  198.   private:
  199.     mutex_type * mMutex;
  200. };
  201. /// Condition variable class.
  202. /// This is a signalling object for synchronizing the execution flow for
  203. /// several threads. Example usage:
  204. /// @code
  205. /// // Shared data and associated mutex and condition variable objects
  206. /// int count;
  207. /// mutex m;
  208. /// condition_variable cond;
  209. ///
  210. /// // Wait for the counter to reach a certain number
  211. /// void wait_counter(int targetCount)
  212. /// {
  213. ///   lock_guard<mutex> guard(m);
  214. ///   while(count < targetCount)
  215. ///     cond.wait(m);
  216. /// }
  217. ///
  218. /// // Increment the counter, and notify waiting threads
  219. /// void increment()
  220. /// {
  221. ///   lock_guard<mutex> guard(m);
  222. ///   ++ count;
  223. ///   cond.notify_all();
  224. /// }
  225. /// @endcode
  226. class condition_variable {
  227.   public:
  228.     /// Constructor.
  229. #if defined(_TTHREAD_WIN32_)
  230.     condition_variable();
  231. #else
  232.     condition_variable()
  233.     {
  234.       pthread_cond_init(&mHandle, NULL);
  235.     }
  236. #endif
  237.     /// Destructor.
  238. #if defined(_TTHREAD_WIN32_)
  239.     ~condition_variable();
  240. #else
  241.     ~condition_variable()
  242.     {
  243.       pthread_cond_destroy(&mHandle);
  244.     }
  245. #endif
  246.     /// Wait for the condition.
  247.     /// The function will block the calling thread until the condition variable
  248.     /// is woken by c notify_one(), c notify_all() or a spurious wake up.
  249.     /// @param[in] aMutex A mutex that will be unlocked when the wait operation
  250.     ///   starts, an locked again as soon as the wait operation is finished.
  251. #if defined(_TTHREAD_WIN32_)
  252.     void wait(mutex &aMutex);
  253. #else
  254.     inline void wait(mutex &aMutex)
  255.     {
  256.       pthread_cond_wait(&mHandle, &aMutex.mHandle);
  257.     }
  258. #endif
  259.     /// Notify one thread that is waiting for the condition.
  260.     /// If at least one thread is blocked waiting for this condition variable,
  261.     /// one will be woken up.
  262.     /// @note Only threads that started waiting prior to this call will be
  263.     /// woken up.
  264. #if defined(_TTHREAD_WIN32_)
  265.     void notify_one();
  266. #else
  267.     inline void notify_one()
  268.     {
  269.       pthread_cond_signal(&mHandle);
  270.     }
  271. #endif
  272.     /// Notify all threads that are waiting for the condition.
  273.     /// All threads that are blocked waiting for this condition variable will
  274.     /// be woken up.
  275.     /// @note Only threads that started waiting prior to this call will be
  276.     /// woken up.
  277. #if defined(_TTHREAD_WIN32_)
  278.     void notify_all();
  279. #else
  280.     inline void notify_all()
  281.     {
  282.       pthread_cond_broadcast(&mHandle);
  283.     }
  284. #endif
  285.   private:
  286. #if defined(_TTHREAD_WIN32_)
  287.     HANDLE mEvents[2];                  ///< Signal and broadcast event HANDLEs.
  288.     unsigned int mWaitersCount;         ///< Count of the number of waiters.
  289.     CRITICAL_SECTION mWaitersCountLock; ///< Serialize access to mWaitersCount.
  290. #else
  291.     pthread_cond_t mHandle;
  292. #endif
  293. };
  294. /// Thread ID.
  295. /// The thread ID is a unique identifier for each thread.
  296. /// @see thread::get_id()
  297. class id {
  298.   public:
  299.     /// Default constructor.
  300.     /// The default constructed ID is that of thread without a thread of
  301.     /// execution.
  302.     id() : mId(0) {};
  303.     id(unsigned long int aId) : mId(aId) {};
  304.     id & operator=(const id &aId)
  305.     {
  306.       mId = aId.mId;
  307.       return *this;
  308.     }
  309.     bool operator==(const id &aId)
  310.     {
  311.       return (aId.mId == mId);
  312.     }
  313.     bool operator!=(const id &aId)
  314.     {
  315.       return (aId.mId != mId);
  316.     }
  317.   private:
  318.     unsigned long int mId;
  319.   friend std::ostream& operator <<(std::ostream &os, const id &obj);
  320. };
  321. /// Thread class.
  322. class thread {
  323.   public:
  324. #if defined(_TTHREAD_WIN32_)
  325.     typedef HANDLE native_handle_type;
  326. #else
  327.     typedef pthread_t native_handle_type;
  328. #endif
  329.     /// Default constructor.
  330.     /// Construct a c thread object without an associated thread of execution
  331.     /// (i.e. non-joinable).
  332.     thread() : mHandle(0), mNotAThread(true)
  333. #if defined(_TTHREAD_WIN32_)
  334.     , mWin32ThreadID(0)
  335. #endif
  336.     {}
  337.     /// Thread starting constructor.
  338.     /// Construct a c thread object with a new thread of execution.
  339.     /// @param[in] aFunction A function pointer to a function of type:
  340.     ///          <tt>void fun(void * arg)</tt>
  341.     /// @param[in] aArg Argument to the thread function.
  342.     /// @note This constructor is not fully compatible with the standard C++
  343.     /// thread class. It is more similar to the pthread_create() (POSIX) and
  344.     /// CreateThread() (Windows) functions.
  345.     thread(void (*aFunction)(void *), void * aArg);
  346.     /// Destructor.
  347.     /// @note If the thread is joinable upon destruction, c std::terminate()
  348.     /// will be called, which terminates the process. It is always wise to do
  349.     /// c join() before deleting a thread object.
  350.     ~thread();
  351.     /// Wait for the thread to finish (join execution flows).
  352.     void join();
  353.     /// Check if the thread is joinable.
  354.     /// A thread object is joinable if it has an associated thread of execution.
  355.     bool joinable() const;
  356.     /// Return the thread ID of a thread object.
  357.     id get_id() const;
  358.     /// Get the native handle for this thread.
  359.     /// @note Under Windows, this is a c HANDLE, and under POSIX systems, this
  360.     /// is a c pthread_t.
  361.     inline native_handle_type native_handle()
  362.     {
  363.       return mHandle;
  364.     }
  365.   private:
  366.     native_handle_type mHandle; ///< Thread handle.
  367.     mutable mutex mDataMutex;   ///< Serializer for access to the thread private data.
  368.     bool mNotAThread;           ///< True if this object is not a thread of execution.
  369. #if defined(_TTHREAD_WIN32_)
  370.     DWORD mWin32ThreadID;       ///< Unique thread ID (filled out by CreateThread).
  371. #endif
  372.     // The internal thread wrapper function needs access to the internal thread
  373.     // data.
  374.     friend void _thread_wrapper(void * aArg);
  375. };
  376. namespace this_thread {
  377.   /// Return the thread ID of the calling thread.
  378.   id get_id();
  379. }
  380. /// Determine the number of processors (CPU cores) in the system.
  381. /// This function is useful for determining the optimal number of threads to
  382. /// use for a task.
  383. /// @return Number of processors in the system.
  384. int number_of_processors();
  385. }
  386. #endif // _TINYTHREAD_H_