Thread.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #pragma once
  6. #include <AnKi/Util/StdTypes.h>
  7. #include <AnKi/Util/Array.h>
  8. #include <AnKi/Util/Atomic.h>
  9. #include <AnKi/Util/BitSet.h>
  10. #include <thread>
  11. #if ANKI_SIMD_SSE
  12. # include <xmmintrin.h>
  13. #endif
  14. #if ANKI_POSIX
  15. # include <pthread.h>
  16. # include <semaphore.h>
  17. #else
  18. # include <AnKi/Util/Win32Minimal.h>
  19. #endif
  20. namespace anki {
  21. /// @addtogroup util_thread
  22. /// @{
  23. /// The thread ID.
  24. /// @memberof Thread
  25. using ThreadId = U64;
  26. /// Core affinity mask.
  27. /// @memberof Thread
  28. using ThreadCoreAffinityMask = BitSet<256, U64>;
  29. /// It holds some information to be passed to the thread's callback.
  30. /// @memberof Thread
  31. class ThreadCallbackInfo
  32. {
  33. public:
  34. void* m_userData;
  35. const char* m_threadName;
  36. };
  37. /// The type of the tread callback.
  38. /// @memberof Thread
  39. using ThreadCallback = Error (*)(ThreadCallbackInfo&);
  40. /// Thread implementation.
  41. class Thread
  42. {
  43. public:
  44. static constexpr U32 kThreadNameMaxLength = 15;
  45. /// Create a thread with or without a name
  46. /// @param[in] name The name of the new thread. Can be nullptr.
  47. Thread(const Char* name);
  48. Thread(const Thread&) = delete;
  49. ~Thread()
  50. {
  51. ANKI_ASSERT(!m_started && "Thread probably not joined");
  52. m_handle = {};
  53. }
  54. Thread& operator=(const Thread&) = delete;
  55. /// Start the thread.
  56. /// @param userData The user data of the thread callback
  57. /// @param callback The thread callback that will be executed
  58. /// @param coreAffintyMask Pin the thread to a number of cores.
  59. void start(void* userData, ThreadCallback callback, const ThreadCoreAffinityMask& coreAffinityMask = ThreadCoreAffinityMask(false));
  60. /// Wait for the thread to finish
  61. /// @return The error code of the thread's callback
  62. Error join();
  63. /// Identify the current thread
  64. static ThreadId getCurrentThreadId()
  65. {
  66. #if ANKI_POSIX
  67. return pthread_self();
  68. #else
  69. return GetCurrentThreadId();
  70. #endif
  71. }
  72. /// Pin to some core.
  73. /// @param coreAffintyMask Pin the thread to a number of cores.
  74. void pinToCores(const ThreadCoreAffinityMask& coreAffintyMask);
  75. /// Name the current thread.
  76. static void setCurrentThreadName(const Char* name);
  77. static const Char* getCurrentThreadName();
  78. private:
  79. /// The system native type.
  80. #if ANKI_POSIX
  81. pthread_t m_handle = {};
  82. #else
  83. HANDLE m_handle = 0; ///< The user date to pass to the callback.
  84. Error m_returnCode = Error::kNone;
  85. #endif
  86. void* m_userData = nullptr; ///< The user date to pass to the callback.
  87. Array<Char, kThreadNameMaxLength + 1> m_name = {}; ///< The name of the thread.
  88. static thread_local Array<Char, kThreadNameMaxLength + 1> m_nameTls;
  89. static constexpr const Char* kDefaultThreadName = "AnKiUnnamed"; ///< the name of an unnamed thread.
  90. ThreadCallback m_callback = nullptr; ///< The callback.
  91. #if ANKI_EXTRA_CHECKS
  92. Bool m_started = false;
  93. #endif
  94. #if ANKI_OS_WINDOWS
  95. static DWORD ANKI_WINAPI threadCallback(LPVOID ud);
  96. #endif
  97. };
  98. /// Mutual exclusion primitive.
  99. class Mutex
  100. {
  101. friend class ConditionVariable;
  102. public:
  103. Mutex()
  104. {
  105. #if ANKI_POSIX
  106. pthread_mutexattr_t attr;
  107. pthread_mutexattr_init(&attr);
  108. pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE);
  109. pthread_mutex_init(&m_handle, &attr);
  110. pthread_mutexattr_destroy(&attr);
  111. #else
  112. InitializeCriticalSection(&m_handle);
  113. #endif
  114. }
  115. Mutex(const Mutex&) = delete;
  116. ~Mutex()
  117. {
  118. #if ANKI_POSIX
  119. pthread_mutex_destroy(&m_handle);
  120. #else
  121. DeleteCriticalSection(&m_handle);
  122. #endif
  123. }
  124. Mutex& operator=(const Mutex&) = delete;
  125. /// Lock
  126. void lock()
  127. {
  128. #if ANKI_POSIX
  129. pthread_mutex_lock(&m_handle);
  130. #else
  131. EnterCriticalSection(&m_handle);
  132. #endif
  133. }
  134. /// Try lock
  135. /// @return True if it was locked successfully
  136. Bool tryLock()
  137. {
  138. #if ANKI_POSIX
  139. return pthread_mutex_trylock(&m_handle) == 0;
  140. #else
  141. const BOOL enter = TryEnterCriticalSection(&m_handle);
  142. return enter != 0;
  143. #endif
  144. }
  145. /// Unlock
  146. void unlock()
  147. {
  148. #if ANKI_POSIX
  149. pthread_mutex_unlock(&m_handle);
  150. #else
  151. LeaveCriticalSection(&m_handle);
  152. #endif
  153. }
  154. private:
  155. /// The system native type.
  156. #if ANKI_POSIX
  157. pthread_mutex_t m_handle = {};
  158. #else
  159. CRITICAL_SECTION m_handle = {};
  160. #endif
  161. };
  162. /// Dummy mutex. Used mainly in tests.
  163. class DummyMutex
  164. {
  165. public:
  166. // Does nothing.
  167. void lock()
  168. {
  169. }
  170. // Does nothing.
  171. void unlock()
  172. {
  173. }
  174. // Does nothing.
  175. Bool tryLock()
  176. {
  177. return true;
  178. }
  179. };
  180. /// Read write mutex.
  181. class RWMutex
  182. {
  183. public:
  184. RWMutex()
  185. {
  186. #if ANKI_POSIX
  187. pthread_rwlockattr_t attr;
  188. pthread_rwlockattr_init(&attr);
  189. pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE);
  190. pthread_rwlock_init(&m_handle, &attr);
  191. pthread_rwlockattr_destroy(&attr);
  192. #else
  193. InitializeSRWLock(&m_handle);
  194. #endif
  195. }
  196. RWMutex(const RWMutex&) = delete;
  197. ~RWMutex()
  198. {
  199. #if ANKI_POSIX
  200. pthread_rwlock_destroy(&m_handle);
  201. #else
  202. // Nothing
  203. #endif
  204. }
  205. RWMutex& operator=(const RWMutex&) = delete;
  206. /// Lock for reading.
  207. void lockRead()
  208. {
  209. #if ANKI_POSIX
  210. pthread_rwlock_rdlock(&m_handle);
  211. #else
  212. AcquireSRWLockShared(&m_handle);
  213. #endif
  214. }
  215. /// Unlock from reading.
  216. void unlockRead()
  217. {
  218. #if ANKI_POSIX
  219. pthread_rwlock_unlock(&m_handle);
  220. #else
  221. ReleaseSRWLockShared(&m_handle);
  222. #endif
  223. }
  224. /// Lock for writing.
  225. void lockWrite()
  226. {
  227. #if ANKI_POSIX
  228. pthread_rwlock_wrlock(&m_handle);
  229. #else
  230. AcquireSRWLockExclusive(&m_handle);
  231. #endif
  232. }
  233. /// Unlock from writing.
  234. void unlockWrite()
  235. {
  236. #if ANKI_POSIX
  237. pthread_rwlock_unlock(&m_handle);
  238. #else
  239. ReleaseSRWLockExclusive(&m_handle);
  240. #endif
  241. }
  242. private:
  243. #if ANKI_POSIX
  244. pthread_rwlock_t m_handle;
  245. #else
  246. SRWLOCK m_handle;
  247. #endif
  248. };
  249. /// Condition variable.
  250. class ConditionVariable
  251. {
  252. public:
  253. ConditionVariable()
  254. {
  255. #if ANKI_POSIX
  256. pthread_condattr_t attr;
  257. pthread_condattr_init(&attr);
  258. pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE);
  259. pthread_cond_init(&m_handle, &attr);
  260. pthread_condattr_destroy(&attr);
  261. #else
  262. InitializeConditionVariable(&m_handle);
  263. #endif
  264. }
  265. ConditionVariable(const ConditionVariable&) = delete;
  266. ~ConditionVariable()
  267. {
  268. #if ANKI_POSIX
  269. pthread_cond_destroy(&m_handle);
  270. #else
  271. // Nothing
  272. #endif
  273. }
  274. ConditionVariable& operator=(const ConditionVariable&) = delete;
  275. /// Signal one thread
  276. void notifyOne()
  277. {
  278. #if ANKI_POSIX
  279. pthread_cond_signal(&m_handle);
  280. #else
  281. WakeConditionVariable(&m_handle);
  282. #endif
  283. }
  284. /// Signal all threads
  285. void notifyAll()
  286. {
  287. #if ANKI_POSIX
  288. pthread_cond_broadcast(&m_handle);
  289. #else
  290. WakeAllConditionVariable(&m_handle);
  291. #endif
  292. }
  293. /// Bock until signaled.
  294. /// @param mtx The mutex.
  295. void wait(Mutex& mtx)
  296. {
  297. #if ANKI_POSIX
  298. pthread_cond_wait(&m_handle, &mtx.m_handle);
  299. #else
  300. SleepConditionVariableCS(&m_handle, &mtx.m_handle, kMaxU32);
  301. #endif
  302. }
  303. private:
  304. #if ANKI_POSIX
  305. pthread_cond_t m_handle;
  306. #else
  307. CONDITION_VARIABLE m_handle;
  308. #endif
  309. };
  310. /// Mutual exclusion primitive. Like Mutex. It's better than Mutex only if the critical section will be executed in a
  311. /// very short period of time.
  312. class SpinLock
  313. {
  314. public:
  315. SpinLock() = default;
  316. SpinLock(const SpinLock&) = delete;
  317. SpinLock& operator=(const SpinLock&) = delete;
  318. /// Lock.
  319. void lock()
  320. {
  321. for(U spinCount = 0; !tryLock(); ++spinCount)
  322. {
  323. if(spinCount < 16)
  324. {
  325. #if ANKI_SIMD_SSE
  326. _mm_pause();
  327. #endif
  328. }
  329. else
  330. {
  331. std::this_thread::yield();
  332. spinCount = 0;
  333. }
  334. }
  335. }
  336. /// Unlock.
  337. void unlock()
  338. {
  339. m_lock.store(false, AtomicMemoryOrder::kRelease);
  340. }
  341. /// Try to lock.
  342. Bool tryLock()
  343. {
  344. return !m_lock.load(AtomicMemoryOrder::kRelaxed) && !m_lock.exchange(true, AtomicMemoryOrder::kAcquire);
  345. }
  346. private:
  347. Atomic<Bool> m_lock = {false};
  348. };
  349. /// A barrier for thread synchronization. It works almost like boost::barrier.
  350. class Barrier
  351. {
  352. public:
  353. Barrier(U32 count)
  354. {
  355. #if ANKI_POSIX
  356. pthread_barrierattr_t attr;
  357. pthread_barrierattr_init(&attr);
  358. pthread_barrierattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE);
  359. pthread_barrier_init(&m_handle, &attr, count);
  360. pthread_barrierattr_destroy(&attr);
  361. #else
  362. InitializeCriticalSection(&m_mtx);
  363. InitializeConditionVariable(&m_cvar);
  364. m_threshold = count;
  365. m_count = count;
  366. m_generation = 0;
  367. #endif
  368. }
  369. Barrier(const Barrier&) = delete;
  370. ~Barrier()
  371. {
  372. #if ANKI_POSIX
  373. pthread_barrier_destroy(&m_handle);
  374. #else
  375. DeleteCriticalSection(&m_mtx);
  376. #endif
  377. }
  378. Barrier& operator=(const Barrier&) = delete;
  379. /// Wait until all threads call wait().
  380. void wait()
  381. {
  382. #if ANKI_POSIX
  383. pthread_barrier_wait(&m_handle);
  384. #else
  385. EnterCriticalSection(&m_mtx);
  386. const U32 gen = m_generation;
  387. if(--m_count == 0)
  388. {
  389. ++m_generation;
  390. m_count = m_threshold;
  391. WakeAllConditionVariable(&m_cvar);
  392. }
  393. else
  394. {
  395. while(gen == m_generation)
  396. {
  397. SleepConditionVariableCS(&m_cvar, &m_mtx, kMaxU32);
  398. }
  399. }
  400. LeaveCriticalSection(&m_mtx);
  401. #endif
  402. }
  403. private:
  404. #if ANKI_POSIX
  405. pthread_barrier_t m_handle;
  406. #else
  407. CONDITION_VARIABLE m_cvar;
  408. CRITICAL_SECTION m_mtx;
  409. U32 m_threshold;
  410. U32 m_count;
  411. U32 m_generation;
  412. #endif
  413. };
  414. /// Semaphore for thread synchronization.
  415. class Semaphore
  416. {
  417. public:
  418. Semaphore(I32 initialValue)
  419. {
  420. #if ANKI_POSIX
  421. sem_init(&m_handle, 0, initialValue);
  422. #else
  423. ANKI_ASSERT(!"TODO");
  424. (void)initialValue;
  425. #endif
  426. }
  427. Semaphore(const Semaphore&) = delete;
  428. ~Semaphore()
  429. {
  430. #if ANKI_POSIX
  431. sem_destroy(&m_handle);
  432. #else
  433. ANKI_ASSERT(!"TODO");
  434. #endif
  435. }
  436. Semaphore& operator=(const Semaphore&) = delete;
  437. /// Same as sem_wait().
  438. /// @code
  439. /// if(value == 0) wait();
  440. /// --value;
  441. /// @endcode
  442. void wait()
  443. {
  444. #if ANKI_POSIX
  445. sem_wait(&m_handle);
  446. #else
  447. ANKI_ASSERT(!"TODO");
  448. #endif
  449. }
  450. /// Same as sem_post().
  451. /// @code
  452. /// ++value;
  453. /// wakeupWaiters();
  454. /// @endcode
  455. void post()
  456. {
  457. #if ANKI_POSIX
  458. sem_post(&m_handle);
  459. #else
  460. ANKI_ASSERT(!"TODO");
  461. #endif
  462. }
  463. private:
  464. #if ANKI_POSIX
  465. sem_t m_handle;
  466. #endif
  467. };
  468. /// Lock guard. When constructed it locks a TMutex and unlocks it when it gets destroyed.
  469. /// @tparam TMutex Can be Mutex or SpinLock.
  470. template<typename TMutex>
  471. class LockGuard
  472. {
  473. public:
  474. LockGuard(TMutex& mtx)
  475. : m_mtx(&mtx)
  476. {
  477. m_mtx->lock();
  478. }
  479. LockGuard(const LockGuard& b) = delete;
  480. LockGuard(LockGuard&& b)
  481. {
  482. m_mtx = b.m_mtx;
  483. b.m_mtx = nullptr;
  484. }
  485. ~LockGuard()
  486. {
  487. if(m_mtx)
  488. {
  489. m_mtx->unlock();
  490. }
  491. }
  492. LockGuard& operator=(LockGuard&& b) = delete;
  493. LockGuard& operator=(const LockGuard& b) = delete;
  494. private:
  495. TMutex* m_mtx;
  496. };
  497. /// Read lock guard. When constructed it locks a TMutex and unlocks it when it gets destroyed.
  498. template<typename TMutex>
  499. class RLockGuard
  500. {
  501. public:
  502. RLockGuard(TMutex& mtx)
  503. : m_mtx(&mtx)
  504. {
  505. m_mtx->lockRead();
  506. }
  507. RLockGuard(const RLockGuard& b) = delete;
  508. ~RLockGuard()
  509. {
  510. m_mtx->unlockRead();
  511. }
  512. RLockGuard& operator=(const RLockGuard& b) = delete;
  513. private:
  514. TMutex* m_mtx;
  515. };
  516. /// Write lock guard. When constructed it locks a TMutex and unlocks it when it gets destroyed.
  517. template<typename TMutex>
  518. class WLockGuard
  519. {
  520. public:
  521. WLockGuard(TMutex& mtx)
  522. : m_mtx(&mtx)
  523. {
  524. m_mtx->lockWrite();
  525. }
  526. WLockGuard(const WLockGuard& b) = delete;
  527. ~WLockGuard()
  528. {
  529. m_mtx->unlockWrite();
  530. }
  531. WLockGuard& operator=(const WLockGuard& b) = delete;
  532. private:
  533. TMutex* m_mtx;
  534. };
  535. /// @}
  536. } // end namespace anki