thread_pool.hpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. //
  2. // impl/thread_pool.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef BOOST_ASIO_IMPL_THREAD_POOL_HPP
  11. #define BOOST_ASIO_IMPL_THREAD_POOL_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/blocking_executor_op.hpp>
  16. #include <boost/asio/detail/executor_op.hpp>
  17. #include <boost/asio/detail/fenced_block.hpp>
  18. #include <boost/asio/detail/non_const_lvalue.hpp>
  19. #include <boost/asio/detail/type_traits.hpp>
  20. #include <boost/asio/execution_context.hpp>
  21. #include <boost/asio/detail/push_options.hpp>
  22. namespace boost {
  23. namespace asio {
  24. inline thread_pool::executor_type
  25. thread_pool::get_executor() noexcept
  26. {
  27. return executor_type(*this);
  28. }
  29. inline thread_pool::executor_type
  30. thread_pool::executor() noexcept
  31. {
  32. return executor_type(*this);
  33. }
  34. template <typename Allocator, unsigned int Bits>
  35. thread_pool::basic_executor_type<Allocator, Bits>&
  36. thread_pool::basic_executor_type<Allocator, Bits>::operator=(
  37. const basic_executor_type& other) noexcept
  38. {
  39. if (this != &other)
  40. {
  41. thread_pool* old_thread_pool = pool_;
  42. pool_ = other.pool_;
  43. allocator_ = other.allocator_;
  44. bits_ = other.bits_;
  45. if (Bits & outstanding_work_tracked)
  46. {
  47. if (pool_)
  48. pool_->scheduler_.work_started();
  49. if (old_thread_pool)
  50. old_thread_pool->scheduler_.work_finished();
  51. }
  52. }
  53. return *this;
  54. }
  55. template <typename Allocator, unsigned int Bits>
  56. thread_pool::basic_executor_type<Allocator, Bits>&
  57. thread_pool::basic_executor_type<Allocator, Bits>::operator=(
  58. basic_executor_type&& other) noexcept
  59. {
  60. if (this != &other)
  61. {
  62. thread_pool* old_thread_pool = pool_;
  63. pool_ = other.pool_;
  64. allocator_ = std::move(other.allocator_);
  65. bits_ = other.bits_;
  66. if (Bits & outstanding_work_tracked)
  67. {
  68. other.pool_ = 0;
  69. if (old_thread_pool)
  70. old_thread_pool->scheduler_.work_finished();
  71. }
  72. }
  73. return *this;
  74. }
  75. template <typename Allocator, unsigned int Bits>
  76. inline bool thread_pool::basic_executor_type<Allocator,
  77. Bits>::running_in_this_thread() const noexcept
  78. {
  79. return pool_->scheduler_.can_dispatch();
  80. }
  81. template <typename Allocator, unsigned int Bits>
  82. template <typename Function>
  83. void thread_pool::basic_executor_type<Allocator,
  84. Bits>::do_execute(Function&& f, false_type) const
  85. {
  86. typedef decay_t<Function> function_type;
  87. // Invoke immediately if the blocking.possibly property is enabled and we are
  88. // already inside the thread pool.
  89. if ((bits_ & blocking_never) == 0 && pool_->scheduler_.can_dispatch())
  90. {
  91. // Make a local, non-const copy of the function.
  92. function_type tmp(static_cast<Function&&>(f));
  93. #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
  94. try
  95. {
  96. #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
  97. detail::fenced_block b(detail::fenced_block::full);
  98. static_cast<function_type&&>(tmp)();
  99. return;
  100. #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
  101. }
  102. catch (...)
  103. {
  104. pool_->scheduler_.capture_current_exception();
  105. return;
  106. }
  107. #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
  108. }
  109. // Allocate and construct an operation to wrap the function.
  110. typedef detail::executor_op<function_type, Allocator> op;
  111. typename op::ptr p = { detail::addressof(allocator_),
  112. op::ptr::allocate(allocator_), 0 };
  113. p.p = new (p.v) op(static_cast<Function&&>(f), allocator_);
  114. if ((bits_ & relationship_continuation) != 0)
  115. {
  116. BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p,
  117. "thread_pool", pool_, 0, "execute(blk=never,rel=cont)"));
  118. }
  119. else
  120. {
  121. BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p,
  122. "thread_pool", pool_, 0, "execute(blk=never,rel=fork)"));
  123. }
  124. pool_->scheduler_.post_immediate_completion(p.p,
  125. (bits_ & relationship_continuation) != 0);
  126. p.v = p.p = 0;
  127. }
  128. template <typename Allocator, unsigned int Bits>
  129. template <typename Function>
  130. void thread_pool::basic_executor_type<Allocator,
  131. Bits>::do_execute(Function&& f, true_type) const
  132. {
  133. // Obtain a non-const instance of the function.
  134. detail::non_const_lvalue<Function> f2(f);
  135. // Invoke immediately if we are already inside the thread pool.
  136. if (pool_->scheduler_.can_dispatch())
  137. {
  138. #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
  139. try
  140. {
  141. #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
  142. detail::fenced_block b(detail::fenced_block::full);
  143. static_cast<decay_t<Function>&&>(f2.value)();
  144. return;
  145. #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
  146. }
  147. catch (...)
  148. {
  149. std::terminate();
  150. }
  151. #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
  152. }
  153. // Construct an operation to wrap the function.
  154. typedef decay_t<Function> function_type;
  155. detail::blocking_executor_op<function_type> op(f2.value);
  156. BOOST_ASIO_HANDLER_CREATION((*pool_, op,
  157. "thread_pool", pool_, 0, "execute(blk=always)"));
  158. pool_->scheduler_.post_immediate_completion(&op, false);
  159. op.wait();
  160. }
  161. #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  162. template <typename Allocator, unsigned int Bits>
  163. inline thread_pool& thread_pool::basic_executor_type<
  164. Allocator, Bits>::context() const noexcept
  165. {
  166. return *pool_;
  167. }
  168. template <typename Allocator, unsigned int Bits>
  169. inline void thread_pool::basic_executor_type<Allocator,
  170. Bits>::on_work_started() const noexcept
  171. {
  172. pool_->scheduler_.work_started();
  173. }
  174. template <typename Allocator, unsigned int Bits>
  175. inline void thread_pool::basic_executor_type<Allocator,
  176. Bits>::on_work_finished() const noexcept
  177. {
  178. pool_->scheduler_.work_finished();
  179. }
  180. template <typename Allocator, unsigned int Bits>
  181. template <typename Function, typename OtherAllocator>
  182. void thread_pool::basic_executor_type<Allocator, Bits>::dispatch(
  183. Function&& f, const OtherAllocator& a) const
  184. {
  185. typedef decay_t<Function> function_type;
  186. // Invoke immediately if we are already inside the thread pool.
  187. if (pool_->scheduler_.can_dispatch())
  188. {
  189. // Make a local, non-const copy of the function.
  190. function_type tmp(static_cast<Function&&>(f));
  191. detail::fenced_block b(detail::fenced_block::full);
  192. static_cast<function_type&&>(tmp)();
  193. return;
  194. }
  195. // Allocate and construct an operation to wrap the function.
  196. typedef detail::executor_op<function_type, OtherAllocator> op;
  197. typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
  198. p.p = new (p.v) op(static_cast<Function&&>(f), a);
  199. BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p,
  200. "thread_pool", pool_, 0, "dispatch"));
  201. pool_->scheduler_.post_immediate_completion(p.p, false);
  202. p.v = p.p = 0;
  203. }
  204. template <typename Allocator, unsigned int Bits>
  205. template <typename Function, typename OtherAllocator>
  206. void thread_pool::basic_executor_type<Allocator, Bits>::post(
  207. Function&& f, const OtherAllocator& a) const
  208. {
  209. typedef decay_t<Function> function_type;
  210. // Allocate and construct an operation to wrap the function.
  211. typedef detail::executor_op<function_type, OtherAllocator> op;
  212. typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
  213. p.p = new (p.v) op(static_cast<Function&&>(f), a);
  214. BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p,
  215. "thread_pool", pool_, 0, "post"));
  216. pool_->scheduler_.post_immediate_completion(p.p, false);
  217. p.v = p.p = 0;
  218. }
  219. template <typename Allocator, unsigned int Bits>
  220. template <typename Function, typename OtherAllocator>
  221. void thread_pool::basic_executor_type<Allocator, Bits>::defer(
  222. Function&& f, const OtherAllocator& a) const
  223. {
  224. typedef decay_t<Function> function_type;
  225. // Allocate and construct an operation to wrap the function.
  226. typedef detail::executor_op<function_type, OtherAllocator> op;
  227. typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
  228. p.p = new (p.v) op(static_cast<Function&&>(f), a);
  229. BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p,
  230. "thread_pool", pool_, 0, "defer"));
  231. pool_->scheduler_.post_immediate_completion(p.p, true);
  232. p.v = p.p = 0;
  233. }
  234. #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  235. } // namespace asio
  236. } // namespace boost
  237. #include <boost/asio/detail/pop_options.hpp>
  238. #endif // BOOST_ASIO_IMPL_THREAD_POOL_HPP