BsThreadPool.h 6.9 KB

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