1 /* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- 2 Copyright (c) 2010-2012 Marcus Geelnard 3 4 This software is provided 'as-is', without any express or implied 5 warranty. In no event will the authors be held liable for any damages 6 arising from the use of this software. 7 8 Permission is granted to anyone to use this software for any purpose, 9 including commercial applications, and to alter it and redistribute it 10 freely, subject to the following restrictions: 11 12 1. The origin of this software must not be misrepresented; you must not 13 claim that you wrote the original software. If you use this software 14 in a product, an acknowledgment in the product documentation would be 15 appreciated but is not required. 16 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 20 3. This notice may not be removed or altered from any source 21 distribution. 22 */ 23 24 #ifndef _TINYTHREAD_H_ 25 #define _TINYTHREAD_H_ 26 27 /// @file 28 /// @mainpage TinyThread++ API Reference 29 /// 30 /// @section intro_sec Introduction 31 /// TinyThread++ is a minimal, portable implementation of basic threading 32 /// classes for C++. 33 /// 34 /// They closely mimic the functionality and naming of the C++11 standard, and 35 /// should be easily replaceable with the corresponding std:: variants. 36 /// 37 /// @section port_sec Portability 38 /// The Win32 variant uses the native Win32 API for implementing the thread 39 /// classes, while for other systems, the POSIX threads API (pthread) is used. 40 /// 41 /// @section class_sec Classes 42 /// In order to mimic the threading API of the C++11 standard, subsets of 43 /// several classes are provided. The fundamental classes are: 44 /// @li tthread::thread 45 /// @li tthread::mutex 46 /// @li tthread::recursive_mutex 47 /// @li tthread::condition_variable 48 /// @li tthread::lock_guard 49 /// @li tthread::fast_mutex 50 /// @li tthread::atomic 51 /// @li tthread::atomic_flag 52 /// 53 /// @section misc_sec Miscellaneous 54 /// The following special keywords are available: #thread_local. 55 /// 56 /// For more detailed information (including additional classes), browse the 57 /// different sections of this documentation. A good place to start is: 58 /// tinythread.h. 59 60 // Which platform are we on? 61 #if !defined(_TTHREAD_PLATFORM_DEFINED_) 62 #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) 63 #define _TTHREAD_WIN32_ 64 #else 65 #define _TTHREAD_POSIX_ 66 #endif 67 #define _TTHREAD_PLATFORM_DEFINED_ 68 #endif 69 70 // Platform specific includes 71 #if defined(_TTHREAD_WIN32_) 72 #ifndef WIN32_LEAN_AND_MEAN 73 #define WIN32_LEAN_AND_MEAN 74 #define __UNDEF_LEAN_AND_MEAN 75 #endif 76 #include <windows.h> 77 #ifdef __UNDEF_LEAN_AND_MEAN 78 #undef WIN32_LEAN_AND_MEAN 79 #undef __UNDEF_LEAN_AND_MEAN 80 #endif 81 #else 82 #include <pthread.h> 83 #include <signal.h> 84 #include <sched.h> 85 #include <unistd.h> 86 #endif 87 88 // Generic includes 89 #include <ostream> 90 91 /// TinyThread++ version (major number). 92 #define TINYTHREAD_VERSION_MAJOR 1 93 /// TinyThread++ version (minor number). 94 #define TINYTHREAD_VERSION_MINOR 2 95 /// TinyThread++ version (full version). 96 #define TINYTHREAD_VERSION (TINYTHREAD_VERSION_MAJOR * 100 + TINYTHREAD_VERSION_MINOR) 97 98 // Do we have a fully featured C++11 compiler? 99 #if (__cplusplus > 199711L) || (defined(__STDCXX_VERSION__) && (__STDCXX_VERSION__ >= 201001L)) 100 #define _TTHREAD_CPP11_ 101 #endif 102 103 // ...at least partial C++11? 104 #if defined(_TTHREAD_CPP11_) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__) 105 #define _TTHREAD_CPP11_PARTIAL_ 106 #endif 107 108 // Do we have atomic builtins? 109 #if defined(__GNUC__) && defined(__GNUC_MINOR__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) 110 #define _TTHREAD_HAS_ATOMIC_BUILTINS_ 111 #endif 112 113 // Check if we can support the assembly language atomic operations? 114 // Note: on MSVC, inline assembly is not supported on the ARM and x64 processors 115 // (see https://docs.microsoft.com/en-us/cpp/assembler/inline/inline-assembler) 116 #if (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) || \ 117 (defined(_MSC_VER) && (defined(_M_IX86))) || \ 118 (defined(__GNUC__) && (defined(__ppc__))) 119 #define _TTHREAD_HAS_ASM_ATOMICS_ 120 #endif 121 122 // Macro for disabling assignments of objects. 123 #ifdef _TTHREAD_CPP11_PARTIAL_ 124 #define _TTHREAD_DISABLE_ASSIGNMENT(name) \ 125 name(const name&) = delete; \ 126 name& operator=(const name&) = delete; 127 #else 128 #define _TTHREAD_DISABLE_ASSIGNMENT(name) \ 129 name(const name&); \ 130 name& operator=(const name&); 131 #endif 132 133 /// @def thread_local 134 /// Thread local storage keyword. 135 /// A variable that is declared with the @c thread_local keyword makes the 136 /// value of the variable local to each thread (known as thread-local storage, 137 /// or TLS). Example usage: 138 /// @code 139 /// // This variable is local to each thread. 140 /// thread_local int variable; 141 /// @endcode 142 /// @note The @c thread_local keyword is a macro that maps to the corresponding 143 /// compiler directive (e.g. @c __declspec(thread)). While the C++11 standard 144 /// allows for non-trivial types (e.g. classes with constructors and 145 /// destructors) to be declared with the @c thread_local keyword, most pre-C++11 146 /// compilers only allow for trivial types (e.g. @c int). So, to guarantee 147 /// portable code, only use trivial types for thread local storage. 148 /// @note This directive is currently not supported on Mac OS X (it will give 149 /// a compiler error), since compile-time TLS is not supported in the Mac OS X 150 /// executable format. Also, some older versions of MinGW (before GCC 4.x) do 151 /// not support this directive. 152 /// @hideinitializer 153 154 #if !defined(_TTHREAD_CPP11_) && !defined(thread_local) 155 #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) 156 #define thread_local __thread 157 #else 158 #define thread_local __declspec(thread) 159 #endif 160 #endif 161 162 163 /// Main name space for TinyThread++. 164 /// This namespace is more or less equivalent to the @c std namespace for the 165 /// C++11 thread classes. For instance, the tthread::mutex class corresponds to 166 /// the std::mutex class. 167 namespace tthread { 168 169 /// Mutex class. 170 /// This is a mutual exclusion object for synchronizing access to shared 171 /// memory areas for several threads. The mutex is non-recursive (i.e. a 172 /// program may deadlock if the thread that owns a mutex object calls lock() 173 /// on that object). 174 /// @see recursive_mutex 175 class mutex { 176 public: 177 /// Constructor. mutex()178 mutex() 179 #if defined(_TTHREAD_WIN32_) 180 : mAlreadyLocked(false) 181 #endif 182 { 183 #if defined(_TTHREAD_WIN32_) 184 InitializeCriticalSection(&mHandle); 185 #else 186 pthread_mutex_init(&mHandle, NULL); 187 #endif 188 } 189 190 /// Destructor. ~mutex()191 ~mutex() 192 { 193 #if defined(_TTHREAD_WIN32_) 194 DeleteCriticalSection(&mHandle); 195 #else 196 pthread_mutex_destroy(&mHandle); 197 #endif 198 } 199 200 /// Lock the mutex. 201 /// The method will block the calling thread until a lock on the mutex can 202 /// be obtained. The mutex remains locked until @c unlock() is called. 203 /// @see lock_guard lock()204 inline void lock() 205 { 206 #if defined(_TTHREAD_WIN32_) 207 EnterCriticalSection(&mHandle); 208 while(mAlreadyLocked) Sleep(1000); // Simulate deadlock... 209 mAlreadyLocked = true; 210 #else 211 pthread_mutex_lock(&mHandle); 212 #endif 213 } 214 215 /// Try to lock the mutex. 216 /// The method will try to lock the mutex. If it fails, the function will 217 /// return immediately (non-blocking). 218 /// @return @c true if the lock was acquired, or @c false if the lock could 219 /// not be acquired. try_lock()220 inline bool try_lock() 221 { 222 #if defined(_TTHREAD_WIN32_) 223 bool ret = (TryEnterCriticalSection(&mHandle) ? true : false); 224 if(ret && mAlreadyLocked) 225 { 226 LeaveCriticalSection(&mHandle); 227 ret = false; 228 } 229 return ret; 230 #else 231 return (pthread_mutex_trylock(&mHandle) == 0) ? true : false; 232 #endif 233 } 234 235 /// Unlock the mutex. 236 /// If any threads are waiting for the lock on this mutex, one of them will 237 /// be unblocked. unlock()238 inline void unlock() 239 { 240 #if defined(_TTHREAD_WIN32_) 241 mAlreadyLocked = false; 242 LeaveCriticalSection(&mHandle); 243 #else 244 pthread_mutex_unlock(&mHandle); 245 #endif 246 } 247 248 _TTHREAD_DISABLE_ASSIGNMENT(mutex) 249 250 private: 251 #if defined(_TTHREAD_WIN32_) 252 CRITICAL_SECTION mHandle; 253 bool mAlreadyLocked; 254 #else 255 pthread_mutex_t mHandle; 256 #endif 257 258 friend class condition_variable; 259 }; 260 261 /// Recursive mutex class. 262 /// This is a mutual exclusion object for synchronizing access to shared 263 /// memory areas for several threads. The mutex is recursive (i.e. a thread 264 /// may lock the mutex several times, as long as it unlocks the mutex the same 265 /// number of times). 266 /// @see mutex 267 class recursive_mutex { 268 public: 269 /// Constructor. recursive_mutex()270 recursive_mutex() 271 { 272 #if defined(_TTHREAD_WIN32_) 273 InitializeCriticalSection(&mHandle); 274 #else 275 pthread_mutexattr_t attr; 276 pthread_mutexattr_init(&attr); 277 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 278 pthread_mutex_init(&mHandle, &attr); 279 #endif 280 } 281 282 /// Destructor. ~recursive_mutex()283 ~recursive_mutex() 284 { 285 #if defined(_TTHREAD_WIN32_) 286 DeleteCriticalSection(&mHandle); 287 #else 288 pthread_mutex_destroy(&mHandle); 289 #endif 290 } 291 292 /// Lock the mutex. 293 /// The method will block the calling thread until a lock on the mutex can 294 /// be obtained. The mutex remains locked until @c unlock() is called. 295 /// @see lock_guard lock()296 inline void lock() 297 { 298 #if defined(_TTHREAD_WIN32_) 299 EnterCriticalSection(&mHandle); 300 #else 301 pthread_mutex_lock(&mHandle); 302 #endif 303 } 304 305 /// Try to lock the mutex. 306 /// The method will try to lock the mutex. If it fails, the function will 307 /// return immediately (non-blocking). 308 /// @return @c true if the lock was acquired, or @c false if the lock could 309 /// not be acquired. try_lock()310 inline bool try_lock() 311 { 312 #if defined(_TTHREAD_WIN32_) 313 return TryEnterCriticalSection(&mHandle) ? true : false; 314 #else 315 return (pthread_mutex_trylock(&mHandle) == 0) ? true : false; 316 #endif 317 } 318 319 /// Unlock the mutex. 320 /// If any threads are waiting for the lock on this mutex, one of them will 321 /// be unblocked. unlock()322 inline void unlock() 323 { 324 #if defined(_TTHREAD_WIN32_) 325 LeaveCriticalSection(&mHandle); 326 #else 327 pthread_mutex_unlock(&mHandle); 328 #endif 329 } 330 331 _TTHREAD_DISABLE_ASSIGNMENT(recursive_mutex) 332 333 private: 334 #if defined(_TTHREAD_WIN32_) 335 CRITICAL_SECTION mHandle; 336 #else 337 pthread_mutex_t mHandle; 338 #endif 339 340 friend class condition_variable; 341 }; 342 343 /// Lock guard class. 344 /// The constructor locks the mutex, and the destructor unlocks the mutex, so 345 /// the mutex will automatically be unlocked when the lock guard goes out of 346 /// scope. Example usage: 347 /// @code 348 /// mutex m; 349 /// int counter; 350 /// 351 /// void increment() 352 /// { 353 /// lock_guard<mutex> guard(m); 354 /// ++ counter; 355 /// } 356 /// @endcode 357 358 template <class T> 359 class lock_guard { 360 public: 361 typedef T mutex_type; 362 lock_guard()363 lock_guard() : mMutex(0) {} 364 365 /// The constructor locks the mutex. lock_guard(mutex_type & aMutex)366 explicit lock_guard(mutex_type &aMutex) 367 { 368 mMutex = &aMutex; 369 mMutex->lock(); 370 } 371 372 /// The destructor unlocks the mutex. ~lock_guard()373 ~lock_guard() 374 { 375 if(mMutex) 376 mMutex->unlock(); 377 } 378 379 private: 380 mutex_type * mMutex; 381 }; 382 383 /// Condition variable class. 384 /// This is a signalling object for synchronizing the execution flow for 385 /// several threads. Example usage: 386 /// @code 387 /// // Shared data and associated mutex and condition variable objects 388 /// int count; 389 /// mutex m; 390 /// condition_variable cond; 391 /// 392 /// // Wait for the counter to reach a certain number 393 /// void wait_counter(int targetCount) 394 /// { 395 /// lock_guard<mutex> guard(m); 396 /// while(count < targetCount) 397 /// cond.wait(m); 398 /// } 399 /// 400 /// // Increment the counter, and notify waiting threads 401 /// void increment() 402 /// { 403 /// lock_guard<mutex> guard(m); 404 /// ++ count; 405 /// cond.notify_all(); 406 /// } 407 /// @endcode 408 class condition_variable { 409 public: 410 /// Constructor. 411 #if defined(_TTHREAD_WIN32_) 412 condition_variable(); 413 #else 414 condition_variable() 415 { 416 pthread_cond_init(&mHandle, NULL); 417 } 418 #endif 419 420 /// Destructor. 421 #if defined(_TTHREAD_WIN32_) 422 ~condition_variable(); 423 #else ~condition_variable()424 ~condition_variable() 425 { 426 pthread_cond_destroy(&mHandle); 427 } 428 #endif 429 430 /// Wait for the condition. 431 /// The function will block the calling thread until the condition variable 432 /// is woken by @c notify_one(), @c notify_all() or a spurious wake up. 433 /// @param[in] aMutex A mutex that will be unlocked when the wait operation 434 /// starts, an locked again as soon as the wait operation is finished. 435 template <class _mutexT> wait(_mutexT & aMutex)436 inline void wait(_mutexT &aMutex) 437 { 438 #if defined(_TTHREAD_WIN32_) 439 // Increment number of waiters 440 EnterCriticalSection(&mWaitersCountLock); 441 ++ mWaitersCount; 442 LeaveCriticalSection(&mWaitersCountLock); 443 444 // Release the mutex while waiting for the condition (will decrease 445 // the number of waiters when done)... 446 aMutex.unlock(); 447 _wait(); 448 aMutex.lock(); 449 #else 450 pthread_cond_wait(&mHandle, &aMutex.mHandle); 451 #endif 452 } 453 454 /// Notify one thread that is waiting for the condition. 455 /// If at least one thread is blocked waiting for this condition variable, 456 /// one will be woken up. 457 /// @note Only threads that started waiting prior to this call will be 458 /// woken up. 459 #if defined(_TTHREAD_WIN32_) 460 void notify_one(); 461 #else notify_one()462 inline void notify_one() 463 { 464 pthread_cond_signal(&mHandle); 465 } 466 #endif 467 468 /// Notify all threads that are waiting for the condition. 469 /// All threads that are blocked waiting for this condition variable will 470 /// be woken up. 471 /// @note Only threads that started waiting prior to this call will be 472 /// woken up. 473 #if defined(_TTHREAD_WIN32_) 474 void notify_all(); 475 #else notify_all()476 inline void notify_all() 477 { 478 pthread_cond_broadcast(&mHandle); 479 } 480 #endif 481 482 _TTHREAD_DISABLE_ASSIGNMENT(condition_variable) 483 484 private: 485 #if defined(_TTHREAD_WIN32_) 486 void _wait(); 487 HANDLE mEvents[2]; ///< Signal and broadcast event HANDLEs. 488 unsigned int mWaitersCount; ///< Count of the number of waiters. 489 CRITICAL_SECTION mWaitersCountLock; ///< Serialize access to mWaitersCount. 490 #else 491 pthread_cond_t mHandle; 492 #endif 493 }; 494 495 /// Memory access order. 496 /// Specifies how non-atomic memory accesses are to be ordered around an atomic 497 /// operation. 498 enum memory_order { 499 memory_order_relaxed, ///< Relaxed ordering: there are no constraints on 500 /// reordering of memory accesses around the atomic 501 /// variable. 502 memory_order_consume, ///< Consume operation: no reads in the current thread 503 /// dependent on the value currently loaded can be 504 /// reordered before this load. This ensures that 505 /// writes to dependent variables in other threads 506 /// that release the same atomic variable are visible 507 /// in the current thread. On most platforms, this 508 /// affects compiler optimization only. 509 memory_order_acquire, ///< Acquire operation: no reads in the current thread 510 /// can be reordered before this load. This ensures 511 /// that all writes in other threads that release the 512 /// same atomic variable are visible in the current 513 /// thread. 514 memory_order_release, ///< Release operation: no writes in the current thread 515 /// can be reordered after this store. This ensures 516 /// that all writes in the current thread are visible 517 /// in other threads that acquire the same atomic 518 /// variable. 519 memory_order_acq_rel, ///< Acquire-release operation: no reads in the current 520 /// thread can be reordered before this load as well 521 /// as no writes in the current thread can be 522 /// reordered after this store. The operation is 523 /// read-modify-write operation. It is ensured that 524 /// all writes in another threads that release the 525 /// same atomic variable are visible before the 526 /// modification and the modification is visible in 527 /// other threads that acquire the same atomic 528 /// variable. 529 memory_order_seq_cst ///< Sequential ordering: The operation has the same 530 /// semantics as acquire-release operation, and 531 /// additionally has sequentially-consistent operation 532 /// ordering. 533 }; 534 535 /// Expression which can be used to initialize atomic_flag to clear state. 536 /// Example usage: 537 /// \code{.cpp} 538 /// tthread::atomic_flag myFlag(ATOMIC_FLAG_INIT); 539 /// \endcode 540 #define ATOMIC_FLAG_INIT 0 541 542 /// Atomic flag class. 543 /// This is an atomic boolean object that provides methods for atmically 544 /// testing, setting and clearing the state of the object. It can be used 545 /// for implementing user space spin-locks, for instance. 546 class atomic_flag { 547 public: atomic_flag()548 atomic_flag() : mFlag(0) 549 { 550 } 551 atomic_flag(int value)552 atomic_flag(int value) : mFlag(value) 553 { 554 } 555 556 /// Atomically test and set the value. 557 /// @param order The memory sycnhronization ordering for this operation. 558 /// @return The value held before this operation. 559 inline bool test_and_set(memory_order order = memory_order_seq_cst) 560 { 561 (void)order; 562 #if defined(_TTHREAD_HAS_ATOMIC_BUILTINS_) 563 return static_cast<bool>(__sync_lock_test_and_set(&mFlag, 1)); 564 #elif defined(_TTHREAD_HAS_ASM_ATOMICS_) 565 int result; 566 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) 567 asm volatile ( 568 "movl $1,%%eax\n\t" 569 "xchg %%eax,%0\n\t" 570 "movl %%eax,%1\n\t" 571 : "=m" (mFlag), "=m" (result) 572 : 573 : "%eax", "memory" 574 ); 575 #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) 576 int *ptrFlag = &mFlag; 577 __asm { 578 mov eax,1 579 mov ecx,ptrFlag 580 xchg eax,[ecx] 581 mov result,eax 582 } 583 #elif defined(__GNUC__) && (defined(__ppc__)) 584 int newFlag = 1; 585 asm volatile ( 586 "\n1:\n\t" 587 "lwarx %0,0,%1\n\t" 588 "cmpwi 0,%0,0\n\t" 589 "bne- 2f\n\t" 590 "stwcx. %2,0,%1\n\t" 591 "bne- 1b\n\t" 592 "isync\n" 593 "2:\n\t" 594 : "=&r" (result) 595 : "r" (&mFlag), "r" (newFlag) 596 : "cr0", "memory" 597 ); 598 #endif 599 return static_cast<bool>(result); 600 #else 601 lock_guard<mutex> guard(mLock); 602 int result = mFlag; 603 mFlag = 1; 604 return static_cast<bool>(result); 605 #endif 606 } 607 608 /// Atomically changes the state to cleared (false). 609 /// @param order The memory sycnhronization ordering for this operation. 610 inline void clear(memory_order order = memory_order_seq_cst) 611 { 612 (void)order; 613 #if defined(_TTHREAD_HAS_ATOMIC_BUILTINS_) 614 __sync_lock_release(&mFlag); 615 #elif defined(_TTHREAD_HAS_ASM_ATOMICS_) 616 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) 617 asm volatile ( 618 "movl $0,%%eax\n\t" 619 "xchg %%eax,%0\n\t" 620 : "=m" (mFlag) 621 : 622 : "%eax", "memory" 623 ); 624 #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) 625 int *ptrFlag = &mFlag; 626 __asm { 627 mov eax,0 628 mov ecx,ptrFlag 629 xchg eax,[ecx] 630 } 631 #elif defined(__GNUC__) && (defined(__ppc__)) 632 asm volatile ( 633 "sync\n\t" // Replace with lwsync where possible? 634 : : : "memory" 635 ); 636 mFlag = 0; 637 #endif 638 #else 639 lock_guard<mutex> guard(mLock); 640 mFlag = 0; 641 #endif 642 } 643 644 _TTHREAD_DISABLE_ASSIGNMENT(atomic_flag) 645 646 private: 647 #if !(defined(_TTHREAD_HAS_ATOMIC_BUILTINS_) || defined(_TTHREAD_HAS_ASM_ATOMICS_)) 648 mutex mLock; 649 #endif // !(_TTHREAD_HAS_ATOMIC_BUILTINS_ || _TTHREAD_HAS_ASM_ATOMICS_) 650 volatile int mFlag; 651 }; 652 653 654 /// Atomic template class. 655 /// An atomic object provides atomic access to an underlying data element of 656 /// the template type T. 657 template<class T> 658 struct atomic { 659 public: atomicatomic660 atomic() : mValue(0) 661 { 662 } 663 atomicatomic664 atomic(T desired) : mValue(desired) 665 { 666 } 667 668 /// Checks whether the atomic operations on the object are lock-free. is_lock_freeatomic669 inline bool is_lock_free() const 670 { 671 #ifdef _TTHREAD_HAS_ATOMIC_BUILTINS_ 672 return true; 673 #else 674 return false; 675 #endif 676 } 677 678 /// Atomically replaces the current value. 679 /// @param desired The new value. 680 /// @param order The memory sycnhronization ordering for this operation. 681 inline void store(T desired, memory_order order = memory_order_seq_cst) 682 { 683 (void)order; 684 #ifdef _TTHREAD_HAS_ATOMIC_BUILTINS_ 685 // FIXME: Use something more suitable here 686 __sync_lock_test_and_set(&mValue, desired); 687 #else 688 lock_guard<mutex> guard(mLock); 689 mValue = desired; 690 #endif 691 } 692 693 /// Atomically loads the current value. 694 /// @param order The memory sycnhronization ordering for this operation. 695 inline T load(memory_order order = memory_order_seq_cst) const 696 { 697 (void)order; 698 #ifdef _TTHREAD_HAS_ATOMIC_BUILTINS_ 699 // FIXME: Use something more suitable here 700 return __sync_add_and_fetch((volatile T*)&mValue, 0); 701 #else 702 lock_guard<mutex> guard(mLock); 703 return mValue; 704 #endif 705 } 706 707 /// Atomically increments the current value. 708 /// Atomically replaces the current value with the result of arithmetic 709 /// addition of the value and arg. The operation is a read-modify-write 710 /// operation. 711 /// @param arg The value to be added to the current value. 712 /// @param order The memory sycnhronization ordering for this operation. 713 inline T fetch_add(T arg, memory_order order = memory_order_seq_cst) 714 { 715 (void)order; 716 #ifdef _TTHREAD_HAS_ATOMIC_BUILTINS_ 717 return __sync_fetch_and_add(&mValue, arg); 718 #else 719 lock_guard<mutex> guard(mLock); 720 T result = mValue; 721 mValue += arg; 722 return result; 723 #endif 724 } 725 726 /// Atomically decrements the current value. 727 /// Atomically replaces the current value with the result of arithmetic 728 /// subtraction of the value and arg. The operation is a read-modify-write 729 /// operation. 730 /// @param arg The value to be subtracted from the current value. 731 /// @param order The memory sycnhronization ordering for this operation. 732 inline T fetch_sub(T arg, memory_order order = memory_order_seq_cst) 733 { 734 (void)order; 735 #ifdef _TTHREAD_HAS_ATOMIC_BUILTINS_ 736 return __sync_fetch_and_sub(&mValue, arg); 737 #else 738 lock_guard<mutex> guard(mLock); 739 T result = mValue; 740 mValue -= arg; 741 return result; 742 #endif 743 } 744 745 /// Atomically replaces the current value. 746 /// Equivalent to store(desired). 747 /// @param desired The new value. 748 /// @return The new value. 749 inline T operator=(T desired) 750 { 751 store(desired); 752 return desired; 753 } 754 755 /// Atomically loads the current value. 756 /// Equivalent to load(). 757 /// @return The current value. Tatomic758 inline operator T() const 759 { 760 return load(); 761 } 762 763 /// Atomic post-increment. 764 /// Equivalent to fetch_add(1) + 1. 765 /// @return The value after the increment operation. 766 inline T operator++() 767 { 768 return fetch_add(1) + 1; 769 } 770 771 /// Atomic pre-increment. 772 /// Equivalent to fetch_add(1). 773 /// @return The value before the increment operation. 774 inline T operator++(int) 775 { 776 return fetch_add(1); 777 } 778 779 /// Atomic post-decrement. 780 /// Equivalent to fetch_sub(1) - 1. 781 /// @return The value a the decrement operation. 782 inline T operator--() 783 { 784 return fetch_sub(1) - 1; 785 } 786 787 /// Atomic pre-decrement. 788 /// Equivalent to fetch_sub(1). 789 /// @return The value before the decrement operation. 790 inline T operator--(int) 791 { 792 return fetch_sub(1); 793 } 794 795 _TTHREAD_DISABLE_ASSIGNMENT(atomic<T>) 796 797 private: 798 #ifndef _TTHREAD_HAS_ATOMIC_BUILTINS_ 799 mutable mutex mLock; 800 #endif // _TTHREAD_HAS_ATOMIC_BUILTINS_ 801 volatile T mValue; 802 }; 803 804 typedef atomic<char> atomic_char; ///< Specialized atomic for type char. 805 typedef atomic<signed char> atomic_schar; ///< Specialized atomic for type signed char. 806 typedef atomic<unsigned char> atomic_uchar; ///< Specialized atomic for type unsigned char. 807 typedef atomic<short> atomic_short; ///< Specialized atomic for type short. 808 typedef atomic<unsigned short> atomic_ushort; ///< Specialized atomic for type unsigned short. 809 typedef atomic<int> atomic_int; ///< Specialized atomic for type int. 810 typedef atomic<unsigned int> atomic_uint; ///< Specialized atomic for type unsigned int. 811 typedef atomic<long> atomic_long; ///< Specialized atomic for type long. 812 typedef atomic<unsigned long> atomic_ulong; ///< Specialized atomic for type unsigned long. 813 typedef atomic<long long> atomic_llong; ///< Specialized atomic for type long long. 814 typedef atomic<unsigned long long> atomic_ullong; ///< Specialized atomic for type unsigned long long. 815 816 /// Thread class. 817 class thread { 818 public: 819 #if defined(_TTHREAD_WIN32_) 820 typedef HANDLE native_handle_type; 821 #else 822 typedef pthread_t native_handle_type; 823 #endif 824 825 class id; 826 827 /// Default constructor. 828 /// Construct a @c thread object without an associated thread of execution 829 /// (i.e. non-joinable). thread()830 thread() : mHandle(0), mWrapper(0) 831 #if defined(_TTHREAD_WIN32_) 832 , mWin32ThreadID(0) 833 #endif 834 {} 835 836 /// Thread starting constructor. 837 /// Construct a @c thread object with a new thread of execution. 838 /// @param[in] aFunction A function pointer to a function of type: 839 /// <tt>void fun(void * arg)</tt> 840 /// @param[in] aArg Argument to the thread function. 841 /// @note This constructor is not fully compatible with the standard C++ 842 /// thread class. It is more similar to the pthread_create() (POSIX) and 843 /// CreateThread() (Windows) functions. 844 thread(void (*aFunction)(void *), void * aArg); 845 846 /// Destructor. 847 /// @note If the thread is joinable upon destruction, @c std::terminate() 848 /// will be called, which terminates the process. It is always wise to do 849 /// @c join() before deleting a thread object. 850 ~thread(); 851 852 /// Wait for the thread to finish (join execution flows). 853 /// After calling @c join(), the thread object is no longer associated with 854 /// a thread of execution (i.e. it is not joinable, and you may not join 855 /// with it nor detach from it). 856 void join(); 857 858 /// Check if the thread is joinable. 859 /// A thread object is joinable if it has an associated thread of execution. 860 bool joinable() const; 861 862 /// Detach from the thread. 863 /// After calling @c detach(), the thread object is no longer assicated with 864 /// a thread of execution (i.e. it is not joinable). The thread continues 865 /// execution without the calling thread blocking, and when the thread 866 /// ends execution, any owned resources are released. 867 void detach(); 868 869 /// Return the thread ID of a thread object. 870 id get_id() const; 871 872 /// Get the native handle for this thread. 873 /// @note Under Windows, this is a @c HANDLE, and under POSIX systems, this 874 /// is a @c pthread_t. native_handle()875 inline native_handle_type native_handle() 876 { 877 return mHandle; 878 } 879 880 /// Determine the number of threads which can possibly execute concurrently. 881 /// This function is useful for determining the optimal number of threads to 882 /// use for a task. 883 /// @return The number of hardware thread contexts in the system. 884 /// @note If this value is not defined, the function returns zero (0). 885 static unsigned hardware_concurrency(); 886 887 _TTHREAD_DISABLE_ASSIGNMENT(thread) 888 889 private: 890 native_handle_type mHandle; ///< Thread handle. 891 void * mWrapper; ///< Thread wrapper info. 892 #if defined(_TTHREAD_WIN32_) 893 unsigned int mWin32ThreadID; ///< Unique thread ID (filled out by _beginthreadex). 894 #endif 895 896 // This is the internal thread wrapper function. 897 #if defined(_TTHREAD_WIN32_) 898 static unsigned WINAPI wrapper_function(void * aArg); 899 #else 900 static void * wrapper_function(void * aArg); 901 #endif 902 }; 903 904 /// Thread ID. 905 /// The thread ID is a unique identifier for each thread. 906 /// @see thread::get_id() 907 class thread::id { 908 public: 909 /// Default constructor. 910 /// The default constructed ID is that of thread without a thread of 911 /// execution. id()912 id() : mId(0) {}; 913 id(unsigned long int aId)914 id(unsigned long int aId) : mId(aId) {}; 915 id(const id & aId)916 id(const id& aId) : mId(aId.mId) {}; 917 918 inline id & operator=(const id &aId) 919 { 920 mId = aId.mId; 921 return *this; 922 } 923 924 inline friend bool operator==(const id &aId1, const id &aId2) 925 { 926 return (aId1.mId == aId2.mId); 927 } 928 929 inline friend bool operator!=(const id &aId1, const id &aId2) 930 { 931 return (aId1.mId != aId2.mId); 932 } 933 934 inline friend bool operator<=(const id &aId1, const id &aId2) 935 { 936 return (aId1.mId <= aId2.mId); 937 } 938 939 inline friend bool operator<(const id &aId1, const id &aId2) 940 { 941 return (aId1.mId < aId2.mId); 942 } 943 944 inline friend bool operator>=(const id &aId1, const id &aId2) 945 { 946 return (aId1.mId >= aId2.mId); 947 } 948 949 inline friend bool operator>(const id &aId1, const id &aId2) 950 { 951 return (aId1.mId > aId2.mId); 952 } 953 954 inline friend std::ostream& operator <<(std::ostream &os, const id &obj) 955 { 956 os << obj.mId; 957 return os; 958 } 959 960 private: 961 unsigned long int mId; 962 }; 963 964 965 // Related to <ratio> - minimal to be able to support chrono. 966 typedef long long __intmax_t; 967 968 /// Minimal implementation of the @c ratio class. This class provides enough 969 /// functionality to implement some basic @c chrono classes. 970 template <__intmax_t N, __intmax_t D = 1> class ratio { 971 public: _as_double()972 static double _as_double() { return double(N) / double(D); } 973 }; 974 975 /// Minimal implementation of the @c chrono namespace. 976 /// The @c chrono namespace provides types for specifying time intervals. 977 namespace chrono { 978 /// Duration template class. This class provides enough functionality to 979 /// implement @c this_thread::sleep_for(). 980 template <class _Rep, class _Period = ratio<1> > class duration { 981 private: 982 _Rep rep_; 983 public: 984 typedef _Rep rep; 985 typedef _Period period; 986 987 /// Construct a duration object with the given duration. 988 template <class _Rep2> duration(const _Rep2 & r)989 explicit duration(const _Rep2& r) : rep_(r) {}; 990 991 /// Return the value of the duration object. count()992 rep count() const 993 { 994 return rep_; 995 } 996 }; 997 998 // Standard duration types. 999 typedef duration<__intmax_t, ratio<1, 1000000000> > nanoseconds; ///< Duration with the unit nanoseconds. 1000 typedef duration<__intmax_t, ratio<1, 1000000> > microseconds; ///< Duration with the unit microseconds. 1001 typedef duration<__intmax_t, ratio<1, 1000> > milliseconds; ///< Duration with the unit milliseconds. 1002 typedef duration<__intmax_t> seconds; ///< Duration with the unit seconds. 1003 typedef duration<__intmax_t, ratio<60> > minutes; ///< Duration with the unit minutes. 1004 typedef duration<__intmax_t, ratio<3600> > hours; ///< Duration with the unit hours. 1005 } 1006 1007 /// The namespace @c this_thread provides methods for dealing with the 1008 /// calling thread. 1009 namespace this_thread { 1010 /// Return the thread ID of the calling thread. 1011 thread::id get_id(); 1012 1013 /// Yield execution to another thread. 1014 /// Offers the operating system the opportunity to schedule another thread 1015 /// that is ready to run on the current processor. yield()1016 inline void yield() 1017 { 1018 #if defined(_TTHREAD_WIN32_) 1019 Sleep(0); 1020 #else 1021 sched_yield(); 1022 #endif 1023 } 1024 1025 /// Blocks the calling thread for a period of time. 1026 /// @param[in] aTime Minimum time to put the thread to sleep. 1027 /// Example usage: 1028 /// @code 1029 /// // Sleep for 100 milliseconds 1030 /// this_thread::sleep_for(chrono::milliseconds(100)); 1031 /// @endcode 1032 /// @note Supported duration types are: nanoseconds, microseconds, 1033 /// milliseconds, seconds, minutes and hours. sleep_for(const chrono::duration<_Rep,_Period> & aTime)1034 template <class _Rep, class _Period> void sleep_for(const chrono::duration<_Rep, _Period>& aTime) 1035 { 1036 #if defined(_TTHREAD_WIN32_) 1037 Sleep(int(double(aTime.count()) * (1000.0 * _Period::_as_double()) + 0.5)); 1038 #else 1039 usleep(int(double(aTime.count()) * (1000000.0 * _Period::_as_double()) + 0.5)); 1040 #endif 1041 } 1042 } 1043 1044 } 1045 1046 // Define/macro cleanup 1047 #undef _TTHREAD_DISABLE_ASSIGNMENT 1048 1049 #endif // _TINYTHREAD_H_ 1050