Thread.h 11 KB

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