Thread.h 10 KB

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