About
User Reference
C++ API
luafaudes
Developer
Links
libFAUDES online
libFAUDES

Sections

Index

cfl_tinythread.cpp

Go to the documentation of this file.
00001 /** @file cfl_tinythread.cpp Minimalistic portable multi-threading */
00002 
00003 /* 
00004 TinyThread++ is a minimal portable threading library by Marcus Geelnard.
00005 
00006 Cosmetic changes for libFAUDES are signed "tmoor"
00007 
00008 We state the original copyright and acknowledge the authors work.
00009 */
00010 
00011 /* 
00012 Copyright (c) 2010-2012 Marcus Geelnard
00013 
00014 This software is provided 'as-is', without any express or implied
00015 warranty. In no event will the authors be held liable for any damages
00016 arising from the use of this software.
00017 
00018 Permission is granted to anyone to use this software for any purpose,
00019 including commercial applications, and to alter it and redistribute it
00020 freely, subject to the following restrictions:
00021 
00022     1. The origin of this software must not be misrepresented; you must not
00023     claim that you wrote the original software. If you use this software
00024     in a product, an acknowledgment in the product documentation would be
00025     appreciated but is not required.
00026 
00027     2. Altered source versions must be plainly marked as such, and must not be
00028     misrepresented as being the original software.
00029 
00030     3. This notice may not be removed or altered from any source
00031     distribution.
00032 */
00033 
00034 // exclude from faudes html docs  
00035 /** @cond FAUDES_EXCLUDE_DOXYGEN */
00036 
00037 #include <exception>
00038 #include "cfl_tinythread.h"
00039 
00040 #if defined(_TTHREAD_POSIX_)
00041   #include <unistd.h>
00042   #include <map>
00043 #elif defined(_TTHREAD_WIN32_)
00044   #include <process.h>
00045 #endif
00046 
00047 
00048 namespace tthread {
00049 
00050 //------------------------------------------------------------------------------
00051 // condition_variable
00052 //------------------------------------------------------------------------------
00053 // NOTE 1: The Win32 implementation of the condition_variable class is based on
00054 // the corresponding implementation in GLFW, which in turn is based on a
00055 // description by Douglas C. Schmidt and Irfan Pyarali:
00056 // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
00057 //
00058 // NOTE 2: Windows Vista actually has native support for condition variables
00059 // (InitializeConditionVariable, WakeConditionVariable, etc), but we want to
00060 // be portable with pre-Vista Windows versions, so TinyThread++ does not use
00061 // Vista condition variables.
00062 //------------------------------------------------------------------------------
00063 
00064 #if defined(_TTHREAD_WIN32_)
00065   #define _CONDITION_EVENT_ONE 0
00066   #define _CONDITION_EVENT_ALL 1
00067 #endif
00068 
00069 #if defined(_TTHREAD_WIN32_)
00070 condition_variable::condition_variable() : mWaitersCount(0)
00071 {
00072   mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL);
00073   mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL);
00074   InitializeCriticalSection(&mWaitersCountLock);
00075 }
00076 #endif
00077 
00078 #if defined(_TTHREAD_WIN32_)
00079 condition_variable::~condition_variable()
00080 {
00081   CloseHandle(mEvents[_CONDITION_EVENT_ONE]);
00082   CloseHandle(mEvents[_CONDITION_EVENT_ALL]);
00083   DeleteCriticalSection(&mWaitersCountLock);
00084 }
00085 #endif
00086 
00087 #if defined(_TTHREAD_WIN32_)
00088 void condition_variable::_wait()
00089 {
00090   // Wait for either event to become signaled due to notify_one() or
00091   // notify_all() being called
00092   int result = WaitForMultipleObjects(2, mEvents, FALSE, INFINITE);
00093 
00094   // Check if we are the last waiter
00095   EnterCriticalSection(&mWaitersCountLock);
00096   -- mWaitersCount;
00097   bool lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) &&
00098                     (mWaitersCount == 0);
00099   LeaveCriticalSection(&mWaitersCountLock);
00100 
00101   // If we are the last waiter to be notified to stop waiting, reset the event
00102   if(lastWaiter)
00103     ResetEvent(mEvents[_CONDITION_EVENT_ALL]);
00104 }
00105 #endif
00106 
00107 #if defined(_TTHREAD_WIN32_)
00108 void condition_variable::notify_one()
00109 {
00110   // Are there any waiters?
00111   EnterCriticalSection(&mWaitersCountLock);
00112   bool haveWaiters = (mWaitersCount > 0);
00113   LeaveCriticalSection(&mWaitersCountLock);
00114 
00115   // If we have any waiting threads, send them a signal
00116   if(haveWaiters)
00117     SetEvent(mEvents[_CONDITION_EVENT_ONE]);
00118 }
00119 #endif
00120 
00121 #if defined(_TTHREAD_WIN32_)
00122 void condition_variable::notify_all()
00123 {
00124   // Are there any waiters?
00125   EnterCriticalSection(&mWaitersCountLock);
00126   bool haveWaiters = (mWaitersCount > 0);
00127   LeaveCriticalSection(&mWaitersCountLock);
00128 
00129   // If we have any waiting threads, send them a signal
00130   if(haveWaiters)
00131     SetEvent(mEvents[_CONDITION_EVENT_ALL]);
00132 }
00133 #endif
00134 
00135 
00136 //------------------------------------------------------------------------------
00137 // POSIX pthread_t to unique thread::id mapping logic.
00138 // Note: Here we use a global thread safe std::map to convert instances of
00139 // pthread_t to small thread identifier numbers (unique within one process).
00140 // This method should be portable across different POSIX implementations.
00141 //------------------------------------------------------------------------------
00142 
00143 #if defined(_TTHREAD_POSIX_)
00144 static thread::id _pthread_t_to_ID(const pthread_t &aHandle)
00145 {
00146   static mutex idMapLock;
00147   static std::map<pthread_t, unsigned long int> idMap;
00148   static unsigned long int idCount(1);
00149 
00150   lock_guard<mutex> guard(idMapLock);
00151   if(idMap.find(aHandle) == idMap.end())
00152     idMap[aHandle] = idCount ++;
00153   return thread::id(idMap[aHandle]);
00154 }
00155 #endif // _TTHREAD_POSIX_
00156 
00157 
00158 //------------------------------------------------------------------------------
00159 // thread
00160 //------------------------------------------------------------------------------
00161 
00162 /// Information to pass to the new thread (what to run).
00163 struct _thread_start_info {
00164   void (*mFunction)(void *); ///< Pointer to the function to be executed.
00165   void * mArg;               ///< Function argument for the thread function.
00166   thread * mThread;          ///< Pointer to the thread object.
00167 };
00168 
00169 // Thread wrapper function.
00170 #if defined(_TTHREAD_WIN32_)
00171 unsigned WINAPI thread::wrapper_function(void * aArg)
00172 #elif defined(_TTHREAD_POSIX_)
00173 void * thread::wrapper_function(void * aArg)
00174 #endif
00175 {
00176   // Get thread startup information
00177   _thread_start_info * ti = (_thread_start_info *) aArg;
00178 
00179   try
00180   {
00181     // Call the actual client thread function
00182     ti->mFunction(ti->mArg);
00183   }
00184   catch(...)
00185   {
00186     // Uncaught exceptions will terminate the application (default behavior
00187     // according to C++11)
00188     std::terminate();
00189   }
00190 
00191   // The thread is no longer executing
00192   lock_guard<mutex> guard(ti->mThread->mDataMutex);
00193   ti->mThread->mNotAThread = true;
00194 
00195   // The thread is responsible for freeing the startup information
00196   delete ti;
00197 
00198   return 0;
00199 }
00200 
00201 thread::thread(void (*aFunction)(void *), void * aArg)
00202 {
00203   // Serialize access to this thread structure
00204   lock_guard<mutex> guard(mDataMutex);
00205 
00206   // Fill out the thread startup information (passed to the thread wrapper,
00207   // which will eventually free it)
00208   _thread_start_info * ti = new _thread_start_info;
00209   ti->mFunction = aFunction;
00210   ti->mArg = aArg;
00211   ti->mThread = this;
00212 
00213   // The thread is now alive
00214   mNotAThread = false;
00215 
00216   // Create the thread
00217 #if defined(_TTHREAD_WIN32_)
00218   mHandle = (HANDLE) _beginthreadex(0, 0, wrapper_function, (void *) ti, 0, &mWin32ThreadID);
00219 #elif defined(_TTHREAD_POSIX_)
00220   if(pthread_create(&mHandle, NULL, wrapper_function, (void *) ti) != 0)
00221     mHandle = 0;
00222 #endif
00223 
00224   // Did we fail to create the thread?
00225   if(!mHandle)
00226   {
00227     mNotAThread = true;
00228     delete ti;
00229   }
00230 }
00231 
00232 thread::~thread()
00233 {
00234   if(joinable())
00235     std::terminate();
00236 }
00237 
00238 void thread::join()
00239 {
00240   if(joinable())
00241   {
00242 #if defined(_TTHREAD_WIN32_)
00243     WaitForSingleObject(mHandle, INFINITE);
00244     CloseHandle(mHandle);
00245 #elif defined(_TTHREAD_POSIX_)
00246     pthread_join(mHandle, NULL);
00247 #endif
00248   }
00249 }
00250 
00251 bool thread::joinable() const
00252 {
00253   mDataMutex.lock();
00254   bool result = !mNotAThread;
00255   mDataMutex.unlock();
00256   return result;
00257 }
00258 
00259 void thread::detach()
00260 {
00261   mDataMutex.lock();
00262   if(!mNotAThread)
00263   {
00264 #if defined(_TTHREAD_WIN32_)
00265     CloseHandle(mHandle);
00266 #elif defined(_TTHREAD_POSIX_)
00267     pthread_detach(mHandle);
00268 #endif
00269     mNotAThread = true;
00270   }
00271   mDataMutex.unlock();
00272 }
00273 
00274 thread::id thread::get_id() const
00275 {
00276   if(!joinable())
00277     return id();
00278 #if defined(_TTHREAD_WIN32_)
00279   return id((unsigned long int) mWin32ThreadID);
00280 #elif defined(_TTHREAD_POSIX_)
00281   return _pthread_t_to_ID(mHandle);
00282 #endif
00283 }
00284 
00285 unsigned thread::hardware_concurrency()
00286 {
00287 #if defined(_TTHREAD_WIN32_)
00288   SYSTEM_INFO si;
00289   GetSystemInfo(&si);
00290   return (int) si.dwNumberOfProcessors;
00291 #elif defined(_SC_NPROCESSORS_ONLN)
00292   return (int) sysconf(_SC_NPROCESSORS_ONLN);
00293 #elif defined(_SC_NPROC_ONLN)
00294   return (int) sysconf(_SC_NPROC_ONLN);
00295 #else
00296   // The standard requires this function to return zero if the number of
00297   // hardware cores could not be determined.
00298   return 0;
00299 #endif
00300 }
00301 
00302 
00303 //------------------------------------------------------------------------------
00304 // this_thread
00305 //------------------------------------------------------------------------------
00306 
00307 thread::id this_thread::get_id()
00308 {
00309 #if defined(_TTHREAD_WIN32_)
00310   return thread::id((unsigned long int) GetCurrentThreadId());
00311 #elif defined(_TTHREAD_POSIX_)
00312   return _pthread_t_to_ID(pthread_self());
00313 #endif
00314 }
00315 
00316 }// namespace
00317 
00318 // exclude from faudes html docs  
00319 /** @endcond  */

libFAUDES 2.22k --- 2013.04.02 --- c++ source docu by doxygen