Thread.h 11 KB

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