libFAUDES
Sections
Index
|
cfl_tinythread.cppGo 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