Thread.h 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. // Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #ifndef ANKI_UTIL_THREAD_H
  6. #define ANKI_UTIL_THREAD_H
  7. #include "anki/util/StdTypes.h"
  8. #include "anki/util/Array.h"
  9. #include "anki/util/NonCopyable.h"
  10. #include <atomic>
  11. #define ANKI_DISABLE_THREADPOOL_THREADING 0
  12. namespace anki {
  13. // Forward
  14. class Threadpool;
  15. /// @addtogroup util_thread
  16. /// @{
  17. /// Thread implementation
  18. class Thread: public NonCopyable
  19. {
  20. public:
  21. using Id = U64;
  22. /// It holds some information to be passed to the thread's callback
  23. class Info
  24. {
  25. public:
  26. void* m_userData;
  27. const char* m_threadName;
  28. };
  29. /// The type of the tread callback
  30. using Callback = Error(*)(Info&);
  31. /// Create a thread with or without a name
  32. /// @param[in] name The name of the new thread. Can be nullptr
  33. Thread(const char* name);
  34. ~Thread();
  35. /// Start the thread
  36. /// @param userData The user data of the thread callback
  37. /// @param callback The thread callback that will be executed
  38. void start(void* userData, Callback callback);
  39. /// Wait for the thread to finish
  40. /// @return The error code of the thread's callback
  41. ANKI_USE_RESULT Error join();
  42. /// Identify the current thread
  43. static Id getCurrentThreadId();
  44. /// @privatesection
  45. /// @{
  46. const char* _getName() const
  47. {
  48. return &m_name[0];
  49. }
  50. void* _getUserData() const
  51. {
  52. return m_userData;
  53. }
  54. Callback _getCallback() const
  55. {
  56. return m_callback;
  57. }
  58. /// @}
  59. private:
  60. void* m_impl = nullptr; ///< The system native type
  61. Array<char, 32> m_name; ///< The name of the thread
  62. Callback m_callback = nullptr; ///< The callback
  63. void* m_userData = nullptr; ///< The user date to pass to the callback
  64. #if ANKI_ASSERTIONS
  65. Bool8 m_started = false;
  66. #endif
  67. };
  68. /// Mutex
  69. class Mutex: public NonCopyable
  70. {
  71. friend class ConditionVariable;
  72. public:
  73. Mutex();
  74. ~Mutex();
  75. /// Lock
  76. void lock();
  77. /// Try lock
  78. /// @return True if it was locked successfully
  79. Bool tryLock();
  80. /// Unlock
  81. void unlock();
  82. private:
  83. void* m_impl = nullptr; ///< The system native type
  84. };
  85. /// Condition variable
  86. class ConditionVariable: public NonCopyable
  87. {
  88. public:
  89. ConditionVariable();
  90. ~ConditionVariable();
  91. /// Signal one thread
  92. void notifyOne();
  93. /// Signal all threads
  94. void notifyAll();
  95. /// Bock until signaled.
  96. /// @param mtx The mutex.
  97. void wait(Mutex& mtx);
  98. private:
  99. void* m_impl = nullptr; ///< The system native type
  100. };
  101. /// Spin lock. Good if the critical section will be executed in a short period
  102. /// of time
  103. class SpinLock: public NonCopyable
  104. {
  105. public:
  106. /// Lock
  107. void lock()
  108. {
  109. while(m_lock.test_and_set(std::memory_order_acquire))
  110. {}
  111. }
  112. /// Unlock
  113. void unlock()
  114. {
  115. m_lock.clear(std::memory_order_release);
  116. }
  117. private:
  118. std::atomic_flag m_lock = ATOMIC_FLAG_INIT;
  119. };
  120. /// Lock guard. When constructed it locks a TMutex and unlocks it when it gets
  121. /// destroyed.
  122. template<typename TMutex>
  123. class LockGuard
  124. {
  125. public:
  126. LockGuard(TMutex& mtx)
  127. : m_mtx(&mtx)
  128. {
  129. m_mtx->lock();
  130. }
  131. ~LockGuard()
  132. {
  133. m_mtx->unlock();
  134. }
  135. private:
  136. TMutex* m_mtx;
  137. };
  138. /// A barrier for thread synchronization. It works almost like boost::barrier
  139. class Barrier: public NonCopyable
  140. {
  141. public:
  142. Barrier(U32 count);
  143. ~Barrier();
  144. /// Wait until all threads call wait().
  145. Bool wait();
  146. private:
  147. void* m_impl = nullptr;
  148. };
  149. // Forward
  150. namespace detail {
  151. class ThreadpoolThread;
  152. }
  153. /// Parallel task dispatcher. You feed it with tasks and sends them for
  154. /// execution in parallel and then waits for all to finish
  155. class Threadpool: public NonCopyable
  156. {
  157. friend class detail::ThreadpoolThread;
  158. public:
  159. static constexpr U MAX_THREADS = 32; ///< An absolute limit
  160. /// A task assignment for a Threadpool
  161. class Task
  162. {
  163. public:
  164. virtual ~Task()
  165. {}
  166. virtual Error operator()(U32 taskId, PtrSize threadsCount) = 0;
  167. /// Chose a starting and end index
  168. static void choseStartEnd(U32 taskId, PtrSize threadsCount,
  169. PtrSize elementsCount, PtrSize& start, PtrSize& end)
  170. {
  171. F32 tid = taskId;
  172. F32 div = F32(elementsCount) / threadsCount;
  173. start = PtrSize(tid * div);
  174. end = PtrSize((tid + 1.0) * div);
  175. }
  176. };
  177. /// Constructor
  178. Threadpool(U32 threadsCount);
  179. ~Threadpool();
  180. /// Assign a task to a working thread
  181. /// @param slot The slot of the task
  182. /// @param task The task. If it's nullptr then a dummy task will be assigned
  183. void assignNewTask(U32 slot, Task* task);
  184. /// Wait for all tasks to finish.
  185. /// @return The error code in one of the worker threads.
  186. ANKI_USE_RESULT Error waitForAllThreadsToFinish()
  187. {
  188. #if !ANKI_DISABLE_THREADPOOL_THREADING
  189. m_barrier.wait();
  190. #endif
  191. Error err = m_err;
  192. m_err = ErrorCode::NONE;
  193. return err;
  194. }
  195. PtrSize getThreadsCount() const
  196. {
  197. return m_threadsCount;
  198. }
  199. private:
  200. /// A dummy task for a Threadpool
  201. class DummyTask: public Task
  202. {
  203. public:
  204. Error operator()(U32 taskId, PtrSize threadsCount)
  205. {
  206. (void)taskId;
  207. (void)threadsCount;
  208. return ErrorCode::NONE;
  209. }
  210. };
  211. #if !ANKI_DISABLE_THREADPOOL_THREADING
  212. Barrier m_barrier; ///< Synchronization barrier
  213. detail::ThreadpoolThread* m_threads = nullptr; ///< Threads array
  214. #endif
  215. U8 m_threadsCount = 0;
  216. Error m_err = ErrorCode::NONE;
  217. static DummyTask m_dummyTask;
  218. };
  219. /// @}
  220. } // end namespace anki
  221. #endif