BsThreadPool.h 7.0 KB

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