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

操作系统开发

开发平台:

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. #include <exception>
  19. #include "tinythread.h"
  20. #if defined(_TTHREAD_POSIX_)
  21.   #include <unistd.h>
  22.   #include <map>
  23. #endif
  24. namespace tthread {
  25. //------------------------------------------------------------------------------
  26. // id << operator
  27. //------------------------------------------------------------------------------
  28. std::ostream& operator <<(std::ostream &os, const tthread::id &obj)
  29. {
  30.   os << obj.mId;
  31.   return os;
  32. }
  33. //------------------------------------------------------------------------------
  34. // condition_variable
  35. //------------------------------------------------------------------------------
  36. // NOTE 1: The Win32 implementation of the condition_variable class is based on
  37. // the corresponding implementation in GLFW, which in turn is based on a
  38. // description by Douglas C. Schmidt and Irfan Pyarali:
  39. // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
  40. //
  41. // NOTE 2: Windows Vista actually has native support for condition variables
  42. // (InitializeConditionVariable, WakeConditionVariable, etc), but we want to
  43. // be portable with pre-Vista Windows version, so TinyThread++ does not use
  44. // Vista condition variables.
  45. //------------------------------------------------------------------------------
  46. #if defined(_TTHREAD_WIN32_)
  47.   #define _CONDITION_EVENT_ONE 0
  48.   #define _CONDITION_EVENT_ALL 1
  49. #endif
  50. #if defined(_TTHREAD_WIN32_)
  51. condition_variable::condition_variable()
  52. {
  53.   mWaitersCount = 0;
  54.   mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL);
  55.   mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL);
  56.   InitializeCriticalSection(&mWaitersCountLock);
  57. }
  58. #endif
  59. #if defined(_TTHREAD_WIN32_)
  60. condition_variable::~condition_variable()
  61. {
  62.   CloseHandle(mEvents[_CONDITION_EVENT_ONE]);
  63.   CloseHandle(mEvents[_CONDITION_EVENT_ALL]);
  64.   DeleteCriticalSection(&mWaitersCountLock);
  65. }
  66. #endif
  67. #if defined(_TTHREAD_WIN32_)
  68. void condition_variable::wait(mutex &aMutex)
  69. {
  70.   // Increment number of waiters
  71.   EnterCriticalSection(&mWaitersCountLock);
  72.   ++ mWaitersCount;
  73.   LeaveCriticalSection(&mWaitersCountLock);
  74.   // It's ok to release the mutex here since Win32 manual-reset events maintain
  75.   // state when used with SetEvent()
  76.   LeaveCriticalSection(&aMutex.mHandle);
  77.   // Wait for either event to become signaled due to notify_one() or
  78.   // notify_all() being called
  79.   int result = WaitForMultipleObjects(2, mEvents, FALSE, INFINITE);
  80.   // Check if we are the last waiter
  81.   EnterCriticalSection(&mWaitersCountLock);
  82.   -- mWaitersCount;
  83.   bool lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) &&
  84.                     (mWaitersCount == 0);
  85.   LeaveCriticalSection(&mWaitersCountLock);
  86.   // If we are the last waiter to be notified to stop waiting, reset the event
  87.   if(lastWaiter)
  88.     ResetEvent(mEvents[_CONDITION_EVENT_ALL]);
  89.   // Reacquire the mutex
  90.   EnterCriticalSection(&aMutex.mHandle);
  91. }
  92. #endif
  93. #if defined(_TTHREAD_WIN32_)
  94. void condition_variable::notify_one()
  95. {
  96.   // Are there any waiters?
  97.   EnterCriticalSection(&mWaitersCountLock);
  98.   bool haveWaiters = (mWaitersCount > 0);
  99.   LeaveCriticalSection(&mWaitersCountLock);
  100.   // If we have any waiting threads, send them a signal
  101.   if(haveWaiters)
  102.     SetEvent(mEvents[_CONDITION_EVENT_ONE]);
  103. }
  104. #endif
  105. #if defined(_TTHREAD_WIN32_)
  106. void condition_variable::notify_all()
  107. {
  108.   // Are there any waiters?
  109.   EnterCriticalSection(&mWaitersCountLock);
  110.   bool haveWaiters = (mWaitersCount > 0);
  111.   LeaveCriticalSection(&mWaitersCountLock);
  112.   // If we have any waiting threads, send them a signal
  113.   if(haveWaiters)
  114.     SetEvent(mEvents[_CONDITION_EVENT_ALL]);
  115. }
  116. #endif
  117. #if defined(_TTHREAD_POSIX_)
  118. //------------------------------------------------------------------------------
  119. // POSIX pthread_t to unique tinythread::id mapping logic.
  120. // Note: Here we use a global thread safe std:map to convert instances of
  121. // pthread_t to small thread identifier numbers (unique within one process).
  122. // This method should be portable across different POSIX implementations.
  123. //------------------------------------------------------------------------------
  124. // pthread_t -> ID map variables
  125. static mutex _gIdMapLock;
  126. static std::map<pthread_t, unsigned long int> _gIdMap;
  127. static unsigned long int _gIdCount(1);
  128. // This function converts a pthread_t "handle" to a unique thread id.
  129. static id _pthread_t_to_ID(const pthread_t &aHandle)
  130. {
  131.   lock_guard<mutex> guard(_gIdMapLock);
  132.   if(_gIdMap.find(aHandle) == _gIdMap.end())
  133.     _gIdMap[aHandle] = _gIdCount ++;
  134.   return id(_gIdMap[aHandle]);
  135. }
  136. #endif // _TTHREAD_POSIX_
  137. //------------------------------------------------------------------------------
  138. // thread
  139. //------------------------------------------------------------------------------
  140. /// Information to pass to the new thread (what to run).
  141. struct _ThreadStartInfo {
  142.   void (*mFunction)(void *); ///< Pointer to the function to be executed.
  143.   void * mArg;               ///< Function argument for the thread function.
  144.   thread * mThread;          ///< Pointer to the thread object.
  145. };
  146. // Thread wrapper function.
  147. void _thread_wrapper(void * aArg)
  148. {
  149.   // Get thread startup information
  150.   _ThreadStartInfo * ti = (_ThreadStartInfo *) aArg;
  151.   try
  152.   {
  153.     // Call the actual client thread function
  154.     ti->mFunction(ti->mArg);
  155.   }
  156.   catch(...)
  157.   {
  158.     // Uncaught exceptions will terminate the application (default behavior
  159.     // according to the C++0x draft)
  160.     std::terminate();
  161.   }
  162.   // The thread is no longer executing
  163.   lock_guard<mutex> guard(ti->mThread->mDataMutex);
  164.   ti->mThread->mNotAThread = true;
  165.   // The thread is responsible for freeing the startup information
  166.   delete ti;
  167. }
  168. // System specific thread wrapper function.
  169. #if defined(_TTHREAD_WIN32_)
  170. DWORD WINAPI _sys_thread_wrapper(LPVOID aArg)
  171. {
  172.   _thread_wrapper((void *) aArg);
  173.   return 0;
  174. }
  175. #else
  176. void * _sys_thread_wrapper(void * aArg)
  177. {
  178.   _thread_wrapper(aArg);
  179.   return 0;
  180. }
  181. #endif
  182. thread::thread(void (*aFunction)(void *), void * aArg)
  183. {
  184.   // Serialize access to this thread structure
  185.   lock_guard<mutex> guard(mDataMutex);
  186.   // Fill out the thread startup information (passed to the thread wrapper,
  187.   // which will eventually free it)
  188.   _ThreadStartInfo * ti = new _ThreadStartInfo;
  189.   ti->mFunction = aFunction;
  190.   ti->mArg = aArg;
  191.   ti->mThread = this;
  192.   // The thread is now alive
  193.   mNotAThread = false;
  194. #if defined(_TTHREAD_WIN32_)
  195.   // Create the thread
  196.   mHandle = CreateThread(0, 0, _sys_thread_wrapper, (LPVOID) ti, 0, &mWin32ThreadID);
  197.   if(!mHandle)
  198.     mNotAThread = true;
  199. #else
  200.   // Create the thread
  201.   if(pthread_create(&mHandle, NULL, _sys_thread_wrapper, (void *) ti) != 0)
  202.   {
  203.     mHandle = 0;
  204.     mNotAThread = true;
  205.   }
  206. #endif
  207. }
  208. thread::~thread()
  209. {
  210.   if(joinable())
  211.     std::terminate();
  212. }
  213. void thread::join()
  214. {
  215.   if(joinable())
  216.   {
  217. #if defined(_TTHREAD_WIN32_)
  218.     WaitForSingleObject(mHandle, INFINITE);
  219. #else
  220.     pthread_join(mHandle, NULL);
  221. #endif
  222.   }
  223. }
  224. bool thread::joinable() const
  225. {
  226.   mDataMutex.lock();
  227.   bool result = !mNotAThread;
  228.   mDataMutex.unlock();
  229.   return result;
  230. }
  231. id thread::get_id() const
  232. {
  233.   if(!joinable())
  234.     return id();
  235. #if defined(_TTHREAD_WIN32_)
  236.   return id((unsigned long int) mWin32ThreadID);
  237. #else
  238.   return _pthread_t_to_ID(mHandle);
  239. #endif
  240. }
  241. //------------------------------------------------------------------------------
  242. // this_thread
  243. //------------------------------------------------------------------------------
  244. id this_thread::get_id()
  245. {
  246. #if defined(_TTHREAD_WIN32_)
  247.   return id((unsigned long int) GetCurrentThreadId());
  248. #else
  249.   return _pthread_t_to_ID(pthread_self());
  250. #endif
  251. }
  252. //------------------------------------------------------------------------------
  253. // Misc. functions
  254. //------------------------------------------------------------------------------
  255. int number_of_processors()
  256. {
  257. #if defined(_TTHREAD_WIN32_)
  258.   SYSTEM_INFO si;
  259.   GetSystemInfo(&si);
  260.   return (int) si.dwNumberOfProcessors;
  261. #elif defined(_SC_NPROCESSORS_ONLN)
  262.   return (int) sysconf(_SC_NPROCESSORS_ONLN);
  263. #elif defined(_SC_NPROC_ONLN)
  264.   return (int) sysconf(_SC_NPROC_ONLN);
  265. #else
  266.   return 1;
  267. #endif
  268. }
  269. }