libFAUDES
Sections
Index
|
cfl_tinythread.hGo to the documentation of this file.00001 /** @file cfl_tinythread.h Minimalistic portable multi-threading */ 00002 00003 /* 00004 We provide Marcus Gleenard's TinyThread++ for libFAUDES 00005 plug-ins to implement protable multi-threading. This is currently 00006 used in the iodevice plug-ing for networking and edge-detection. 00007 For sake of simplicity, this include file is merged with 00008 fast_mutex.h from the original distribution. We hereby acknowledge 00009 the authors work and state the original copyright below. 00010 00011 Note, however, that core libFAUDES itself is *NOT* thread-safe, 00012 in particular for using global statics for symbol tables. This 00013 may be improved in a subsequent reversion. 00014 00015 */ 00016 00017 /* 00018 Copyright (c) 2010-2012 Marcus Geelnard 00019 00020 This software is provided 'as-is', without any express or implied 00021 warranty. In no event will the authors be held liable for any damages 00022 arising from the use of this software. 00023 00024 Permission is granted to anyone to use this software for any purpose, 00025 including commercial applications, and to alter it and redistribute it 00026 freely, subject to the following restrictions: 00027 00028 1. The origin of this software must not be misrepresented; you must not 00029 claim that you wrote the original software. If you use this software 00030 in a product, an acknowledgment in the product documentation would be 00031 appreciated but is not required. 00032 00033 2. Altered source versions must be plainly marked as such, and must not be 00034 misrepresented as being the original software. 00035 00036 3. This notice may not be removed or altered from any source 00037 distribution. 00038 */ 00039 00040 // exclude from faudes html docs 00041 /** @cond FAUDES_EXCLUDE_DOXYGEN */ 00042 00043 // faudes-style include 00044 #ifndef FAUDES_TINYTHREAD_H 00045 #define FAUDES_TINYTHREAD_H 00046 00047 /* 00048 ****************************************************************** 00049 ****************************************************************** 00050 ****************************************************************** 00051 00052 Original source: "tinythread.h" 00053 00054 Marginal adjustments signed "tmoor" 00055 00056 ****************************************************************** 00057 ****************************************************************** 00058 ****************************************************************** 00059 */ 00060 00061 00062 /// @file 00063 /// @mainpage TinyThread++ API Reference 00064 /// 00065 /// @section intro_sec Introduction 00066 /// TinyThread++ is a minimal, portable implementation of basic threading 00067 /// classes for C++. 00068 /// 00069 /// They closely mimic the functionality and naming of the C++11 standard, and 00070 /// should be easily replaceable with the corresponding std:: variants. 00071 /// 00072 /// @section port_sec Portability 00073 /// The Win32 variant uses the native Win32 API for implementing the thread 00074 /// classes, while for other systems, the POSIX threads API (pthread) is used. 00075 /// 00076 /// @section class_sec Classes 00077 /// In order to mimic the threading API of the C++11 standard, subsets of 00078 /// several classes are provided. The fundamental classes are: 00079 /// @li tthread::thread 00080 /// @li tthread::mutex 00081 /// @li tthread::recursive_mutex 00082 /// @li tthread::condition_variable 00083 /// @li tthread::lock_guard 00084 /// @li tthread::fast_mutex 00085 /// 00086 /// @section misc_sec Miscellaneous 00087 /// The following special keywords are available: #thread_local. 00088 /// 00089 /// For more detailed information (including additional classes), browse the 00090 /// different sections of this documentation. A good place to start is: 00091 /// tinythread.h. 00092 00093 // Which platform are we on? 00094 #if !defined(_TTHREAD_PLATFORM_DEFINED_) 00095 #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) 00096 #define _TTHREAD_WIN32_ 00097 #else 00098 #define _TTHREAD_POSIX_ 00099 #endif 00100 #define _TTHREAD_PLATFORM_DEFINED_ 00101 #endif 00102 00103 // Platform specific includes 00104 #if defined(_TTHREAD_WIN32_) 00105 #ifndef WIN32_LEAN_AND_MEAN 00106 #define WIN32_LEAN_AND_MEAN 00107 #define __UNDEF_LEAN_AND_MEAN 00108 #endif 00109 #include <windows.h> 00110 #ifdef __UNDEF_LEAN_AND_MEAN 00111 #undef WIN32_LEAN_AND_MEAN 00112 #undef __UNDEF_LEAN_AND_MEAN 00113 #endif 00114 #else 00115 #include <pthread.h> 00116 #include <signal.h> 00117 #include <sched.h> 00118 #include <unistd.h> 00119 #endif 00120 00121 // Generic includes 00122 #include <ostream> 00123 00124 /// TinyThread++ version (major number). 00125 #define TINYTHREAD_VERSION_MAJOR 1 00126 /// TinyThread++ version (minor number). 00127 #define TINYTHREAD_VERSION_MINOR 1 00128 /// TinyThread++ version (full version). 00129 #define TINYTHREAD_VERSION (TINYTHREAD_VERSION_MAJOR * 100 + TINYTHREAD_VERSION_MINOR) 00130 00131 // Do we have a fully featured C++11 compiler? 00132 #if (__cplusplus > 199711L) || (defined(__STDCXX_VERSION__) && (__STDCXX_VERSION__ >= 201001L)) 00133 #define _TTHREAD_CPP11_ 00134 #endif 00135 00136 // ...at least partial C++11? 00137 #if defined(_TTHREAD_CPP11_) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__) 00138 #define _TTHREAD_CPP11_PARTIAL_ 00139 #endif 00140 00141 // Macro for disabling assignments of objects. 00142 #ifdef _TTHREAD_CPP11_PARTIAL_ 00143 #define _TTHREAD_DISABLE_ASSIGNMENT(name) \ 00144 name(const name&) = delete; \ 00145 name& operator=(const name&) = delete; 00146 #else 00147 #define _TTHREAD_DISABLE_ASSIGNMENT(name) \ 00148 name(const name&); \ 00149 name& operator=(const name&); 00150 #endif 00151 00152 /// @def thread_local 00153 /// Thread local storage keyword. 00154 /// A variable that is declared with the @c thread_local keyword makes the 00155 /// value of the variable local to each thread (known as thread-local storage, 00156 /// or TLS). Example usage: 00157 /// @code 00158 /// // This variable is local to each thread. 00159 /// thread_local int variable; 00160 /// @endcode 00161 /// @note The @c thread_local keyword is a macro that maps to the corresponding 00162 /// compiler directive (e.g. @c __declspec(thread)). While the C++11 standard 00163 /// allows for non-trivial types (e.g. classes with constructors and 00164 /// destructors) to be declared with the @c thread_local keyword, most pre-C++11 00165 /// compilers only allow for trivial types (e.g. @c int). So, to guarantee 00166 /// portable code, only use trivial types for thread local storage. 00167 /// @note This directive is currently not supported on Mac OS X (it will give 00168 /// a compiler error), since compile-time TLS is not supported in the Mac OS X 00169 /// executable format. Also, some older versions of MinGW (before GCC 4.x) do 00170 /// not support this directive. 00171 /// @hideinitializer 00172 00173 #if !defined(_TTHREAD_CPP11_) && !defined(thread_local) 00174 #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) 00175 #define thread_local __thread 00176 #else 00177 #define thread_local __declspec(thread) 00178 #endif 00179 #endif 00180 00181 00182 /// Main name space for TinyThread++. 00183 /// This namespace is more or less equivalent to the @c std namespace for the 00184 /// C++11 thread classes. For instance, the tthread::mutex class corresponds to 00185 /// the std::mutex class. 00186 namespace tthread { 00187 00188 /// Mutex class. 00189 /// This is a mutual exclusion object for synchronizing access to shared 00190 /// memory areas for several threads. The mutex is non-recursive (i.e. a 00191 /// program may deadlock if the thread that owns a mutex object calls lock() 00192 /// on that object). 00193 /// @see recursive_mutex 00194 class mutex { 00195 public: 00196 /// Constructor. 00197 mutex() 00198 #if defined(_TTHREAD_WIN32_) 00199 : mAlreadyLocked(false) 00200 #endif 00201 { 00202 #if defined(_TTHREAD_WIN32_) 00203 InitializeCriticalSection(&mHandle); 00204 #else 00205 pthread_mutex_init(&mHandle, NULL); 00206 #endif 00207 } 00208 00209 /// Destructor. 00210 ~mutex() 00211 { 00212 #if defined(_TTHREAD_WIN32_) 00213 DeleteCriticalSection(&mHandle); 00214 #else 00215 pthread_mutex_destroy(&mHandle); 00216 #endif 00217 } 00218 00219 /// Lock the mutex. 00220 /// The method will block the calling thread until a lock on the mutex can 00221 /// be obtained. The mutex remains locked until @c unlock() is called. 00222 /// @see lock_guard 00223 inline void lock() 00224 { 00225 #if defined(_TTHREAD_WIN32_) 00226 EnterCriticalSection(&mHandle); 00227 while(mAlreadyLocked) Sleep(1000); // Simulate deadlock... 00228 mAlreadyLocked = true; 00229 #else 00230 pthread_mutex_lock(&mHandle); 00231 #endif 00232 } 00233 00234 /// Try to lock the mutex. 00235 /// The method will try to lock the mutex. If it fails, the function will 00236 /// return immediately (non-blocking). 00237 /// @return @c true if the lock was acquired, or @c false if the lock could 00238 /// not be acquired. 00239 inline bool try_lock() 00240 { 00241 #if defined(_TTHREAD_WIN32_) 00242 bool ret = (TryEnterCriticalSection(&mHandle) ? true : false); 00243 if(ret && mAlreadyLocked) 00244 { 00245 LeaveCriticalSection(&mHandle); 00246 ret = false; 00247 } 00248 return ret; 00249 #else 00250 return (pthread_mutex_trylock(&mHandle) == 0) ? true : false; 00251 #endif 00252 } 00253 00254 /// Unlock the mutex. 00255 /// If any threads are waiting for the lock on this mutex, one of them will 00256 /// be unblocked. 00257 inline void unlock() 00258 { 00259 #if defined(_TTHREAD_WIN32_) 00260 mAlreadyLocked = false; 00261 LeaveCriticalSection(&mHandle); 00262 #else 00263 pthread_mutex_unlock(&mHandle); 00264 #endif 00265 } 00266 00267 _TTHREAD_DISABLE_ASSIGNMENT(mutex) 00268 00269 private: 00270 #if defined(_TTHREAD_WIN32_) 00271 CRITICAL_SECTION mHandle; 00272 bool mAlreadyLocked; 00273 #else 00274 pthread_mutex_t mHandle; 00275 #endif 00276 00277 friend class condition_variable; 00278 }; 00279 00280 /// Recursive mutex class. 00281 /// This is a mutual exclusion object for synchronizing access to shared 00282 /// memory areas for several threads. The mutex is recursive (i.e. a thread 00283 /// may lock the mutex several times, as long as it unlocks the mutex the same 00284 /// number of times). 00285 /// @see mutex 00286 class recursive_mutex { 00287 public: 00288 /// Constructor. 00289 recursive_mutex() 00290 { 00291 #if defined(_TTHREAD_WIN32_) 00292 InitializeCriticalSection(&mHandle); 00293 #else 00294 pthread_mutexattr_t attr; 00295 pthread_mutexattr_init(&attr); 00296 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 00297 pthread_mutex_init(&mHandle, &attr); 00298 #endif 00299 } 00300 00301 /// Destructor. 00302 ~recursive_mutex() 00303 { 00304 #if defined(_TTHREAD_WIN32_) 00305 DeleteCriticalSection(&mHandle); 00306 #else 00307 pthread_mutex_destroy(&mHandle); 00308 #endif 00309 } 00310 00311 /// Lock the mutex. 00312 /// The method will block the calling thread until a lock on the mutex can 00313 /// be obtained. The mutex remains locked until @c unlock() is called. 00314 /// @see lock_guard 00315 inline void lock() 00316 { 00317 #if defined(_TTHREAD_WIN32_) 00318 EnterCriticalSection(&mHandle); 00319 #else 00320 pthread_mutex_lock(&mHandle); 00321 #endif 00322 } 00323 00324 /// Try to lock the mutex. 00325 /// The method will try to lock the mutex. If it fails, the function will 00326 /// return immediately (non-blocking). 00327 /// @return @c true if the lock was acquired, or @c false if the lock could 00328 /// not be acquired. 00329 inline bool try_lock() 00330 { 00331 #if defined(_TTHREAD_WIN32_) 00332 return TryEnterCriticalSection(&mHandle) ? true : false; 00333 #else 00334 return (pthread_mutex_trylock(&mHandle) == 0) ? true : false; 00335 #endif 00336 } 00337 00338 /// Unlock the mutex. 00339 /// If any threads are waiting for the lock on this mutex, one of them will 00340 /// be unblocked. 00341 inline void unlock() 00342 { 00343 #if defined(_TTHREAD_WIN32_) 00344 LeaveCriticalSection(&mHandle); 00345 #else 00346 pthread_mutex_unlock(&mHandle); 00347 #endif 00348 } 00349 00350 _TTHREAD_DISABLE_ASSIGNMENT(recursive_mutex) 00351 00352 private: 00353 #if defined(_TTHREAD_WIN32_) 00354 CRITICAL_SECTION mHandle; 00355 #else 00356 pthread_mutex_t mHandle; 00357 #endif 00358 00359 friend class condition_variable; 00360 }; 00361 00362 /// Lock guard class. 00363 /// The constructor locks the mutex, and the destructor unlocks the mutex, so 00364 /// the mutex will automatically be unlocked when the lock guard goes out of 00365 /// scope. Example usage: 00366 /// @code 00367 /// mutex m; 00368 /// int counter; 00369 /// 00370 /// void increment() 00371 /// { 00372 /// lock_guard<mutex> guard(m); 00373 /// ++ counter; 00374 /// } 00375 /// @endcode 00376 00377 template <class T> 00378 class lock_guard { 00379 public: 00380 typedef T mutex_type; 00381 00382 lock_guard() : mMutex(0) {} 00383 00384 /// The constructor locks the mutex. 00385 explicit lock_guard(mutex_type &aMutex) 00386 { 00387 mMutex = &aMutex; 00388 mMutex->lock(); 00389 } 00390 00391 /// The destructor unlocks the mutex. 00392 ~lock_guard() 00393 { 00394 if(mMutex) 00395 mMutex->unlock(); 00396 } 00397 00398 private: 00399 mutex_type * mMutex; 00400 }; 00401 00402 /// Condition variable class. 00403 /// This is a signalling object for synchronizing the execution flow for 00404 /// several threads. Example usage: 00405 /// @code 00406 /// // Shared data and associated mutex and condition variable objects 00407 /// int count; 00408 /// mutex m; 00409 /// condition_variable cond; 00410 /// 00411 /// // Wait for the counter to reach a certain number 00412 /// void wait_counter(int targetCount) 00413 /// { 00414 /// lock_guard<mutex> guard(m); 00415 /// while(count < targetCount) 00416 /// cond.wait(m); 00417 /// } 00418 /// 00419 /// // Increment the counter, and notify waiting threads 00420 /// void increment() 00421 /// { 00422 /// lock_guard<mutex> guard(m); 00423 /// ++ count; 00424 /// cond.notify_all(); 00425 /// } 00426 /// @endcode 00427 class condition_variable { 00428 public: 00429 /// Constructor. 00430 #if defined(_TTHREAD_WIN32_) 00431 condition_variable(); 00432 #else 00433 condition_variable() 00434 { 00435 pthread_cond_init(&mHandle, NULL); 00436 } 00437 #endif 00438 00439 /// Destructor. 00440 #if defined(_TTHREAD_WIN32_) 00441 ~condition_variable(); 00442 #else 00443 ~condition_variable() 00444 { 00445 pthread_cond_destroy(&mHandle); 00446 } 00447 #endif 00448 00449 /// Wait for the condition. 00450 /// The function will block the calling thread until the condition variable 00451 /// is woken by @c notify_one(), @c notify_all() or a spurious wake up. 00452 /// @param[in] aMutex A mutex that will be unlocked when the wait operation 00453 /// starts, an locked again as soon as the wait operation is finished. 00454 template <class _mutexT> 00455 inline void wait(_mutexT &aMutex) 00456 { 00457 #if defined(_TTHREAD_WIN32_) 00458 // Increment number of waiters 00459 EnterCriticalSection(&mWaitersCountLock); 00460 ++ mWaitersCount; 00461 LeaveCriticalSection(&mWaitersCountLock); 00462 00463 // Release the mutex while waiting for the condition (will decrease 00464 // the number of waiters when done)... 00465 aMutex.unlock(); 00466 _wait(); 00467 aMutex.lock(); 00468 #else 00469 pthread_cond_wait(&mHandle, &aMutex.mHandle); 00470 #endif 00471 } 00472 00473 /// Notify one thread that is waiting for the condition. 00474 /// If at least one thread is blocked waiting for this condition variable, 00475 /// one will be woken up. 00476 /// @note Only threads that started waiting prior to this call will be 00477 /// woken up. 00478 #if defined(_TTHREAD_WIN32_) 00479 void notify_one(); 00480 #else 00481 inline void notify_one() 00482 { 00483 pthread_cond_signal(&mHandle); 00484 } 00485 #endif 00486 00487 /// Notify all threads that are waiting for the condition. 00488 /// All threads that are blocked waiting for this condition variable will 00489 /// be woken up. 00490 /// @note Only threads that started waiting prior to this call will be 00491 /// woken up. 00492 #if defined(_TTHREAD_WIN32_) 00493 void notify_all(); 00494 #else 00495 inline void notify_all() 00496 { 00497 pthread_cond_broadcast(&mHandle); 00498 } 00499 #endif 00500 00501 _TTHREAD_DISABLE_ASSIGNMENT(condition_variable) 00502 00503 private: 00504 #if defined(_TTHREAD_WIN32_) 00505 void _wait(); 00506 HANDLE mEvents[2]; ///< Signal and broadcast event HANDLEs. 00507 unsigned int mWaitersCount; ///< Count of the number of waiters. 00508 CRITICAL_SECTION mWaitersCountLock; ///< Serialize access to mWaitersCount. 00509 #else 00510 pthread_cond_t mHandle; 00511 #endif 00512 }; 00513 00514 00515 /// Thread class. 00516 class thread { 00517 public: 00518 #if defined(_TTHREAD_WIN32_) 00519 typedef HANDLE native_handle_type; 00520 #else 00521 typedef pthread_t native_handle_type; 00522 #endif 00523 00524 class id; 00525 00526 /// Default constructor. 00527 /// Construct a @c thread object without an associated thread of execution 00528 /// (i.e. non-joinable). 00529 thread() : mHandle(0), mNotAThread(true) 00530 #if defined(_TTHREAD_WIN32_) 00531 , mWin32ThreadID(0) 00532 #endif 00533 {} 00534 00535 /// Thread starting constructor. 00536 /// Construct a @c thread object with a new thread of execution. 00537 /// @param[in] aFunction A function pointer to a function of type: 00538 /// <tt>void fun(void * arg)</tt> 00539 /// @param[in] aArg Argument to the thread function. 00540 /// @note This constructor is not fully compatible with the standard C++ 00541 /// thread class. It is more similar to the pthread_create() (POSIX) and 00542 /// CreateThread() (Windows) functions. 00543 thread(void (*aFunction)(void *), void * aArg); 00544 00545 /// Destructor. 00546 /// @note If the thread is joinable upon destruction, @c std::terminate() 00547 /// will be called, which terminates the process. It is always wise to do 00548 /// @c join() before deleting a thread object. 00549 ~thread(); 00550 00551 /// Wait for the thread to finish (join execution flows). 00552 /// After calling @c join(), the thread object is no longer associated with 00553 /// a thread of execution (i.e. it is not joinable, and you may not join 00554 /// with it nor detach from it). 00555 void join(); 00556 00557 /// Check if the thread is joinable. 00558 /// A thread object is joinable if it has an associated thread of execution. 00559 bool joinable() const; 00560 00561 /// Detach from the thread. 00562 /// After calling @c detach(), the thread object is no longer assicated with 00563 /// a thread of execution (i.e. it is not joinable). The thread continues 00564 /// execution without the calling thread blocking, and when the thread 00565 /// ends execution, any owned resources are released. 00566 void detach(); 00567 00568 /// Return the thread ID of a thread object. 00569 id get_id() const; 00570 00571 /// Get the native handle for this thread. 00572 /// @note Under Windows, this is a @c HANDLE, and under POSIX systems, this 00573 /// is a @c pthread_t. 00574 inline native_handle_type native_handle() 00575 { 00576 return mHandle; 00577 } 00578 00579 /// Determine the number of threads which can possibly execute concurrently. 00580 /// This function is useful for determining the optimal number of threads to 00581 /// use for a task. 00582 /// @return The number of hardware thread contexts in the system. 00583 /// @note If this value is not defined, the function returns zero (0). 00584 static unsigned hardware_concurrency(); 00585 00586 _TTHREAD_DISABLE_ASSIGNMENT(thread) 00587 00588 private: 00589 native_handle_type mHandle; ///< Thread handle. 00590 mutable mutex mDataMutex; ///< Serializer for access to the thread private data. 00591 bool mNotAThread; ///< True if this object is not a thread of execution. 00592 #if defined(_TTHREAD_WIN32_) 00593 unsigned int mWin32ThreadID; ///< Unique thread ID (filled out by _beginthreadex). 00594 #endif 00595 00596 // This is the internal thread wrapper function. 00597 #if defined(_TTHREAD_WIN32_) 00598 static unsigned WINAPI wrapper_function(void * aArg); 00599 #else 00600 static void * wrapper_function(void * aArg); 00601 #endif 00602 }; 00603 00604 /// Thread ID. 00605 /// The thread ID is a unique identifier for each thread. 00606 /// @see thread::get_id() 00607 class thread::id { 00608 public: 00609 /// Default constructor. 00610 /// The default constructed ID is that of thread without a thread of 00611 /// execution. 00612 id() : mId(0) {}; 00613 00614 id(unsigned long int aId) : mId(aId) {}; 00615 00616 id(const id& aId) : mId(aId.mId) {}; 00617 00618 inline id & operator=(const id &aId) 00619 { 00620 mId = aId.mId; 00621 return *this; 00622 } 00623 00624 inline friend bool operator==(const id &aId1, const id &aId2) 00625 { 00626 return (aId1.mId == aId2.mId); 00627 } 00628 00629 inline friend bool operator!=(const id &aId1, const id &aId2) 00630 { 00631 return (aId1.mId != aId2.mId); 00632 } 00633 00634 inline friend bool operator<=(const id &aId1, const id &aId2) 00635 { 00636 return (aId1.mId <= aId2.mId); 00637 } 00638 00639 inline friend bool operator<(const id &aId1, const id &aId2) 00640 { 00641 return (aId1.mId < aId2.mId); 00642 } 00643 00644 inline friend bool operator>=(const id &aId1, const id &aId2) 00645 { 00646 return (aId1.mId >= aId2.mId); 00647 } 00648 00649 inline friend bool operator>(const id &aId1, const id &aId2) 00650 { 00651 return (aId1.mId > aId2.mId); 00652 } 00653 00654 inline friend std::ostream& operator <<(std::ostream &os, const id &obj) 00655 { 00656 os << obj.mId; 00657 return os; 00658 } 00659 00660 private: 00661 unsigned long int mId; 00662 }; 00663 00664 00665 // Related to <ratio> - minimal to be able to support chrono. 00666 __extension__ typedef long long __intmax_t; // tmoor: "extension" for g++/osx/pedantic 00667 00668 /// Minimal implementation of the @c ratio class. This class provides enough 00669 /// functionality to implement some basic @c chrono classes. 00670 template <__intmax_t N, __intmax_t D = 1> class ratio { 00671 public: 00672 static double _as_double() { return double(N) / double(D); } 00673 }; 00674 00675 /// Minimal implementation of the @c chrono namespace. 00676 /// The @c chrono namespace provides types for specifying time intervals. 00677 namespace chrono { 00678 /// Duration template class. This class provides enough functionality to 00679 /// implement @c this_thread::sleep_for(). 00680 template <class _Rep, class _Period = ratio<1> > class duration { 00681 private: 00682 _Rep rep_; 00683 public: 00684 typedef _Rep rep; 00685 typedef _Period period; 00686 00687 /// Construct a duration object with the given duration. 00688 template <class _Rep2> 00689 explicit duration(const _Rep2& r) : rep_(r) {} // no colon ; ? tmoor 00690 00691 /// Return the value of the duration object. 00692 rep count() const 00693 { 00694 return rep_; 00695 } 00696 }; 00697 00698 // Standard duration types. 00699 typedef duration<__intmax_t, ratio<1, 1000000000> > nanoseconds; ///< Duration with the unit nanoseconds. 00700 typedef duration<__intmax_t, ratio<1, 1000000> > microseconds; ///< Duration with the unit microseconds. 00701 typedef duration<__intmax_t, ratio<1, 1000> > milliseconds; ///< Duration with the unit milliseconds. 00702 typedef duration<__intmax_t> seconds; ///< Duration with the unit seconds. 00703 typedef duration<__intmax_t, ratio<60> > minutes; ///< Duration with the unit minutes. 00704 typedef duration<__intmax_t, ratio<3600> > hours; ///< Duration with the unit hours. 00705 } 00706 00707 /// The namespace @c this_thread provides methods for dealing with the 00708 /// calling thread. 00709 namespace this_thread { 00710 /// Return the thread ID of the calling thread. 00711 thread::id get_id(); 00712 00713 /// Yield execution to another thread. 00714 /// Offers the operating system the opportunity to schedule another thread 00715 /// that is ready to run on the current processor. 00716 inline void yield() 00717 { 00718 #if defined(_TTHREAD_WIN32_) 00719 Sleep(0); 00720 #else 00721 sched_yield(); 00722 #endif 00723 } 00724 00725 /// Blocks the calling thread for a period of time. 00726 /// @param[in] aTime Minimum time to put the thread to sleep. 00727 /// Example usage: 00728 /// @code 00729 /// // Sleep for 100 milliseconds 00730 /// this_thread::sleep_for(chrono::milliseconds(100)); 00731 /// @endcode 00732 /// @note Supported duration types are: nanoseconds, microseconds, 00733 /// milliseconds, seconds, minutes and hours. 00734 template <class _Rep, class _Period> void sleep_for(const chrono::duration<_Rep, _Period>& aTime) 00735 { 00736 #if defined(_TTHREAD_WIN32_) 00737 Sleep(int(double(aTime.count()) * (1000.0 * _Period::_as_double()) + 0.5)); 00738 #else 00739 usleep(int(double(aTime.count()) * (1000000.0 * _Period::_as_double()) + 0.5)); 00740 #endif 00741 } 00742 } 00743 00744 } // end: namespace 00745 00746 // Define/macro cleanup 00747 #undef _TTHREAD_DISABLE_ASSIGNMENT 00748 00749 00750 /* 00751 ****************************************************************** 00752 ****************************************************************** 00753 ****************************************************************** 00754 00755 Original source: "fast_mutex.h" 00756 00757 ****************************************************************** 00758 ****************************************************************** 00759 ****************************************************************** 00760 */ 00761 00762 // Check if we can support the assembly language level implementation (otherwise 00763 // revert to the system API) 00764 #if (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) || \ 00765 (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))) || \ 00766 (defined(__GNUC__) && (defined(__ppc__))) 00767 #define _FAST_MUTEX_ASM_ 00768 #else 00769 #define _FAST_MUTEX_SYS_ 00770 #endif 00771 00772 #if defined(_TTHREAD_WIN32_) 00773 #ifndef WIN32_LEAN_AND_MEAN 00774 #define WIN32_LEAN_AND_MEAN 00775 #define __UNDEF_LEAN_AND_MEAN 00776 #endif 00777 #include <windows.h> 00778 #ifdef __UNDEF_LEAN_AND_MEAN 00779 #undef WIN32_LEAN_AND_MEAN 00780 #undef __UNDEF_LEAN_AND_MEAN 00781 #endif 00782 #else 00783 #ifdef _FAST_MUTEX_ASM_ 00784 #include <sched.h> 00785 #else 00786 #include <pthread.h> 00787 #endif 00788 #endif 00789 00790 namespace tthread { 00791 00792 /// Fast mutex class. 00793 /// This is a mutual exclusion object for synchronizing access to shared 00794 /// memory areas for several threads. It is similar to the tthread::mutex class, 00795 /// but instead of using system level functions, it is implemented as an atomic 00796 /// spin lock with very low CPU overhead. 00797 /// 00798 /// The \c fast_mutex class is NOT compatible with the \c condition_variable 00799 /// class (however, it IS compatible with the \c lock_guard class). It should 00800 /// also be noted that the \c fast_mutex class typically does not provide 00801 /// as accurate thread scheduling as a the standard \c mutex class does. 00802 /// 00803 /// Because of the limitations of the class, it should only be used in 00804 /// situations where the mutex needs to be locked/unlocked very frequently. 00805 /// 00806 /// @note The "fast" version of this class relies on inline assembler language, 00807 /// which is currently only supported for 32/64-bit Intel x86/AMD64 and 00808 /// PowerPC architectures on a limited number of compilers (GNU g++ and MS 00809 /// Visual C++). 00810 /// For other architectures/compilers, system functions are used instead. 00811 class fast_mutex { 00812 public: 00813 /// Constructor. 00814 #if defined(_FAST_MUTEX_ASM_) 00815 fast_mutex() : mLock(0) {} 00816 #else 00817 fast_mutex() 00818 { 00819 #if defined(_TTHREAD_WIN32_) 00820 InitializeCriticalSection(&mHandle); 00821 #elif defined(_TTHREAD_POSIX_) 00822 pthread_mutex_init(&mHandle, NULL); 00823 #endif 00824 } 00825 #endif 00826 00827 #if !defined(_FAST_MUTEX_ASM_) 00828 /// Destructor. 00829 ~fast_mutex() 00830 { 00831 #if defined(_TTHREAD_WIN32_) 00832 DeleteCriticalSection(&mHandle); 00833 #elif defined(_TTHREAD_POSIX_) 00834 pthread_mutex_destroy(&mHandle); 00835 #endif 00836 } 00837 #endif 00838 00839 /// Lock the mutex. 00840 /// The method will block the calling thread until a lock on the mutex can 00841 /// be obtained. The mutex remains locked until \c unlock() is called. 00842 /// @see lock_guard 00843 inline void lock() 00844 { 00845 #if defined(_FAST_MUTEX_ASM_) 00846 bool gotLock; 00847 do { 00848 gotLock = try_lock(); 00849 if(!gotLock) 00850 { 00851 #if defined(_TTHREAD_WIN32_) 00852 Sleep(0); 00853 #elif defined(_TTHREAD_POSIX_) 00854 sched_yield(); 00855 #endif 00856 } 00857 } while(!gotLock); 00858 #else 00859 #if defined(_TTHREAD_WIN32_) 00860 EnterCriticalSection(&mHandle); 00861 #elif defined(_TTHREAD_POSIX_) 00862 pthread_mutex_lock(&mHandle); 00863 #endif 00864 #endif 00865 } 00866 00867 /// Try to lock the mutex. 00868 /// The method will try to lock the mutex. If it fails, the function will 00869 /// return immediately (non-blocking). 00870 /// @return \c true if the lock was acquired, or \c false if the lock could 00871 /// not be acquired. 00872 inline bool try_lock() 00873 { 00874 #if defined(_FAST_MUTEX_ASM_) 00875 int oldLock; 00876 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) 00877 asm volatile ( 00878 "movl $1,%%eax\n\t" 00879 "xchg %%eax,%0\n\t" 00880 "movl %%eax,%1\n\t" 00881 : "=m" (mLock), "=m" (oldLock) 00882 : 00883 : "%eax", "memory" 00884 ); 00885 #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) 00886 int *ptrLock = &mLock; 00887 __asm { 00888 mov eax,1 00889 mov ecx,ptrLock 00890 xchg eax,[ecx] 00891 mov oldLock,eax 00892 } 00893 #elif defined(__GNUC__) && (defined(__ppc__)) 00894 int newLock = 1; 00895 asm volatile ( 00896 "\n1:\n\t" 00897 "lwarx %0,0,%1\n\t" 00898 "cmpwi 0,%0,0\n\t" 00899 "bne- 2f\n\t" 00900 "stwcx. %2,0,%1\n\t" 00901 "bne- 1b\n\t" 00902 "isync\n" 00903 "2:\n\t" 00904 : "=&r" (oldLock) 00905 : "r" (&mLock), "r" (newLock) 00906 : "cr0", "memory" 00907 ); 00908 #endif 00909 return (oldLock == 0); 00910 #else 00911 #if defined(_TTHREAD_WIN32_) 00912 return TryEnterCriticalSection(&mHandle) ? true : false; 00913 #elif defined(_TTHREAD_POSIX_) 00914 return (pthread_mutex_trylock(&mHandle) == 0) ? true : false; 00915 #endif 00916 #endif 00917 } 00918 00919 /// Unlock the mutex. 00920 /// If any threads are waiting for the lock on this mutex, one of them will 00921 /// be unblocked. 00922 inline void unlock() 00923 { 00924 #if defined(_FAST_MUTEX_ASM_) 00925 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) 00926 asm volatile ( 00927 "movl $0,%%eax\n\t" 00928 "xchg %%eax,%0\n\t" 00929 : "=m" (mLock) 00930 : 00931 : "%eax", "memory" 00932 ); 00933 #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) 00934 int *ptrLock = &mLock; 00935 __asm { 00936 mov eax,0 00937 mov ecx,ptrLock 00938 xchg eax,[ecx] 00939 } 00940 #elif defined(__GNUC__) && (defined(__ppc__)) 00941 asm volatile ( 00942 "sync\n\t" // Replace with lwsync where possible? 00943 : : : "memory" 00944 ); 00945 mLock = 0; 00946 #endif 00947 #else 00948 #if defined(_TTHREAD_WIN32_) 00949 LeaveCriticalSection(&mHandle); 00950 #elif defined(_TTHREAD_POSIX_) 00951 pthread_mutex_unlock(&mHandle); 00952 #endif 00953 #endif 00954 } 00955 00956 private: 00957 #if defined(_FAST_MUTEX_ASM_) 00958 int mLock; 00959 #else 00960 #if defined(_TTHREAD_WIN32_) 00961 CRITICAL_SECTION mHandle; 00962 #elif defined(_TTHREAD_POSIX_) 00963 pthread_mutex_t mHandle; 00964 #endif 00965 #endif 00966 }; 00967 00968 } // end: namespace 00969 00970 00971 #endif // FAUDES_TINYTHREAD_H // tmoor 00972 00973 // exclude from faudes html docs 00974 /** @endcond */ 00975 |
libFAUDES 2.22k --- 2013.04.02 --- c++ source docu by doxygen