BsThreadPool.h 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. #pragma once
  2. #include "BsPrerequisitesUtil.h"
  3. #include "BsModule.h"
  4. namespace BansheeEngine
  5. {
  6. /** @addtogroup Threading
  7. * @{
  8. */
  9. class ThreadPool;
  10. /** Handle to a thread managed by ThreadPool. */
  11. class BS_UTILITY_EXPORT HThread
  12. {
  13. public:
  14. HThread();
  15. HThread(ThreadPool* pool, UINT32 threadId);
  16. /** Block the calling thread until the thread this handle points to completes. */
  17. void blockUntilComplete();
  18. private:
  19. UINT32 mThreadId;
  20. ThreadPool* mPool;
  21. };
  22. /** @cond INTERNAL */
  23. /** Wrapper around a thread that is used within ThreadPool. */
  24. class BS_UTILITY_EXPORT PooledThread
  25. {
  26. public:
  27. PooledThread(const String& name);
  28. virtual ~PooledThread();
  29. /** Initializes the pooled thread. Must be called right after the object is constructed. */
  30. void initialize();
  31. /**
  32. * Starts executing the given worker method.
  33. *
  34. * @note
  35. * Caller must ensure worker method is not null and that the thread is currently idle, otherwise undefined behavior
  36. * will occur.
  37. */
  38. void start(std::function<void()> workerMethod, UINT32 id);
  39. /**
  40. * Attempts to join the currently running thread and destroys it. Caller must ensure that any worker method
  41. * currently running properly returns, otherwise this will block indefinitely.
  42. */
  43. void destroy();
  44. /** Returns true if the thread is idle and new worker method can be scheduled on it. */
  45. bool isIdle();
  46. /** Returns how long has the thread been idle. Value is undefined if thread is not idle. */
  47. time_t idleTime();
  48. /** Sets a name of the thread. */
  49. void setName(const String& name);
  50. /** Gets unique ID of the currently executing thread. */
  51. UINT32 getId() const;
  52. /** Blocks the current thread until this thread completes. Returns immediately if the thread is idle. */
  53. void blockUntilComplete();
  54. /** Called when the thread is first created. */
  55. virtual void onThreadStarted(const String& name) = 0;
  56. /** Called when the thread is being shut down. */
  57. virtual void onThreadEnded(const String& name) = 0;
  58. protected:
  59. friend class HThread;
  60. /** Primary worker method that is ran when the thread is first initialized. */
  61. void run();
  62. protected:
  63. std::function<void()> mWorkerMethod;
  64. String mName;
  65. UINT32 mId;
  66. bool mIdle;
  67. bool mThreadStarted;
  68. bool mThreadReady;
  69. time_t mIdleTime;
  70. BS_THREAD_TYPE* mThread;
  71. BS_MUTEX(mMutex);
  72. BS_THREAD_SYNCHRONISER(mStartedCond);
  73. BS_THREAD_SYNCHRONISER(mReadyCond);
  74. BS_THREAD_SYNCHRONISER(mWorkerEndedCond);
  75. };
  76. /**
  77. * @copydoc PooledThread
  78. *
  79. * @tparam ThreadPolicy Allows you specify a policy with methods that will get called whenever a new thread is created
  80. * or when a thread is destroyed.
  81. */
  82. template<class ThreadPolicy>
  83. class TPooledThread : public PooledThread
  84. {
  85. public:
  86. TPooledThread(const String& name)
  87. :PooledThread(name)
  88. { }
  89. /** @copydoc PooledThread::onThreadStarted */
  90. void onThreadStarted(const String& name) override
  91. {
  92. ThreadPolicy::onThreadStarted(name);
  93. }
  94. /** @copydoc PooledThread::onThreadEnded */
  95. void onThreadEnded(const String& name) override
  96. {
  97. ThreadPolicy::onThreadEnded(name);
  98. }
  99. };
  100. /** @endcond */
  101. /**
  102. * Class that maintains a pool of threads we can easily retrieve and use for any task. This saves on the cost of
  103. * creating and destroying threads.
  104. */
  105. class BS_UTILITY_EXPORT ThreadPool : public Module<ThreadPool>
  106. {
  107. public:
  108. /**
  109. * @brief Constructs a new thread pool
  110. *
  111. * @param[in] threadCapacity Default thread capacity, the pool will always try to keep this many threads available.
  112. * @param[in] maxCapacity (optional) Maximum number of threads the pool can create. If we go over this limit an
  113. * exception will be thrown.
  114. * @param[in] idleTimeout (optional) How many seconds do threads need to be idle before we remove them from the pool.
  115. */
  116. ThreadPool(UINT32 threadCapacity, UINT32 maxCapacity = 16, UINT32 idleTimeout = 60);
  117. virtual ~ThreadPool();
  118. /**
  119. * Find an unused thread (or creates a new one) and runs the specified worker method on it.
  120. *
  121. * @param[in] name A name you may use for more easily identifying the thread.
  122. * @param[in] workerMethod The worker method to be called by the thread.
  123. *
  124. * @return A thread handle you may use for monitoring the thread execution.
  125. */
  126. HThread run(const String& name, std::function<void()> workerMethod);
  127. /**
  128. * Stops all threads and destroys them. Caller must ensure each threads worker method returns otherwise this will
  129. * never return.
  130. */
  131. void stopAll();
  132. /** Clear any unused threads that are over the capacity. */
  133. void clearUnused();
  134. /** Returns the number of unused threads in the pool. */
  135. UINT32 getNumAvailable() const;
  136. /** Returns the number of running threads in the pool. */
  137. UINT32 getNumActive() const;
  138. /** Returns the total number of created threads in the pool (both running and unused). */
  139. UINT32 getNumAllocated() const;
  140. protected:
  141. friend class HThread;
  142. Vector<PooledThread*> mThreads;
  143. /** Creates a new thread to be used by the pool. */
  144. virtual PooledThread* createThread(const String& name) = 0;
  145. /** Destroys the specified thread. Caller needs to make sure the thread is actually shut down beforehand. */
  146. void destroyThread(PooledThread* thread);
  147. /**
  148. * Returns the first unused thread if one exists, otherwise creates a new one.
  149. *
  150. * @param[in] name Name to assign the thread.
  151. *
  152. * @note Throws an exception if we have reached our maximum thread capacity.
  153. */
  154. PooledThread* getThread(const String& name);
  155. UINT32 mDefaultCapacity;
  156. UINT32 mMaxCapacity;
  157. UINT32 mIdleTimeout;
  158. UINT32 mAge;
  159. std::atomic_uint mUniqueId;
  160. BS_MUTEX(mMutex);
  161. };
  162. /** @cond INTERNAL */
  163. /** Policy used for thread start & end used by the ThreadPool. */
  164. class ThreadNoPolicy
  165. {
  166. public:
  167. static void onThreadStarted(const String& name) { }
  168. static void onThreadEnded(const String& name) { }
  169. };
  170. /**
  171. * @copydoc ThreadPool
  172. *
  173. * @tparam ThreadPolicy Allows you specify a policy with methods that will get called whenever a new thread is created
  174. * or when a thread is destroyed.
  175. */
  176. template<class ThreadPolicy = ThreadNoPolicy>
  177. class TThreadPool : public ThreadPool
  178. {
  179. public:
  180. TThreadPool(UINT32 threadCapacity, UINT32 maxCapacity = 16, UINT32 idleTimeout = 60)
  181. :ThreadPool(threadCapacity, maxCapacity, idleTimeout)
  182. {
  183. }
  184. protected:
  185. /** @copydoc ThreadPool::createThread */
  186. PooledThread* createThread(const String& name) override
  187. {
  188. PooledThread* newThread = bs_new<TPooledThread<ThreadPolicy>>(name);
  189. newThread->initialize();
  190. return newThread;
  191. }
  192. };
  193. /** @endcond */
  194. /** @} */
  195. }