Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-16 08:38:11

0001 //
0002 // thread_pool.hpp
0003 // ~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_THREAD_POOL_HPP
0012 #define BOOST_ASIO_THREAD_POOL_HPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <boost/asio/detail/config.hpp>
0019 #include <boost/asio/detail/atomic_count.hpp>
0020 #include <boost/asio/detail/scheduler.hpp>
0021 #include <boost/asio/detail/thread_group.hpp>
0022 #include <boost/asio/execution.hpp>
0023 #include <boost/asio/execution_context.hpp>
0024 
0025 #include <boost/asio/detail/push_options.hpp>
0026 
0027 namespace boost {
0028 namespace asio {
0029 namespace detail {
0030   struct thread_pool_bits
0031   {
0032     static constexpr unsigned int blocking_never = 1;
0033     static constexpr unsigned int blocking_always = 2;
0034     static constexpr unsigned int blocking_mask = 3;
0035     static constexpr unsigned int relationship_continuation = 4;
0036     static constexpr unsigned int outstanding_work_tracked = 8;
0037   };
0038 } // namespace detail
0039 
0040 /// A simple fixed-size thread pool.
0041 /**
0042  * The thread pool class is an execution context where functions are permitted
0043  * to run on one of a fixed number of threads.
0044  *
0045  * @par Thread Safety
0046  * @e Distinct @e objects: Safe.@n
0047  * @e Shared @e objects: Safe, with the specific exceptions of the join()
0048  * wait() and notify_fork() functions. The join() and wait() functions must not
0049  * be called at the same time as other calls to join() or wait() on the same
0050  * pool. The notify_fork() function should not be called while any thread_pool
0051  * function, or any function on an I/O object that is associated with the
0052  * thread_pool, is being called in another thread. (In effect, this means that
0053  * notify_fork() is safe only on a thread pool that has no internal or attached
0054  * threads at the time.)
0055  *
0056  * @par Submitting tasks to the pool
0057  *
0058  * To submit functions to the thread pool, use the @ref boost::asio::dispatch,
0059  * @ref boost::asio::post or @ref boost::asio::defer free functions.
0060  *
0061  * For example:
0062  *
0063  * @code void my_task()
0064  * {
0065  *   ...
0066  * }
0067  *
0068  * ...
0069  *
0070  * // Launch the pool with four threads.
0071  * boost::asio::thread_pool pool(4);
0072  *
0073  * // Submit a function to the pool.
0074  * boost::asio::post(pool, my_task);
0075  *
0076  * // Submit a lambda object to the pool.
0077  * boost::asio::post(pool,
0078  *     []()
0079  *     {
0080  *       ...
0081  *     });
0082  *
0083  * // Wait for all tasks in the pool to complete.
0084  * pool.join(); @endcode
0085  */
0086 class thread_pool
0087   : public execution_context
0088 {
0089 public:
0090   template <typename Allocator, unsigned int Bits>
0091   class basic_executor_type;
0092 
0093   template <typename Allocator, unsigned int Bits>
0094   friend class basic_executor_type;
0095 
0096   /// Executor used to submit functions to a thread pool.
0097   typedef basic_executor_type<std::allocator<void>, 0> executor_type;
0098 
0099 #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0100   /// Constructs a pool with an automatically determined number of threads.
0101   BOOST_ASIO_DECL thread_pool();
0102 
0103   /// Constructs a pool with an automatically determined number of threads.
0104   /**
0105    * @param a An allocator that will be used for allocating objects that are
0106    * associated with the execution context, such as services and internal state
0107    * for I/O objects.
0108    */
0109   template <typename Allocator>
0110   thread_pool(allocator_arg_t, const Allocator& a);
0111 #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0112 
0113   /// Constructs a pool with a specified number of threads.
0114   /**
0115    * @param num_threads The number of threads required.
0116    */
0117   BOOST_ASIO_DECL explicit thread_pool(std::size_t num_threads);
0118 
0119   /// Constructs a pool with a specified number of threads.
0120   /**
0121    * @param num_threads The number of threads required.
0122    *
0123    * @param a An allocator that will be used for allocating objects that are
0124    * associated with the execution context, such as services and internal state
0125    * for I/O objects.
0126    */
0127   template <typename Allocator>
0128   thread_pool(allocator_arg_t, const Allocator& a, std::size_t num_threads);
0129 
0130   /// Constructs a pool with a specified number of threads.
0131   /**
0132    * Construct with a service maker, to create an initial set of services that
0133    * will be installed into the execution context at construction time.
0134    *
0135    * @param num_threads The number of threads required.
0136    *
0137    * @param initial_services Used to create the initial services. The @c make
0138    * function will be called once at the end of execution_context construction.
0139    */
0140   BOOST_ASIO_DECL thread_pool(std::size_t num_threads,
0141       const execution_context::service_maker& initial_services);
0142 
0143   /// Constructs a pool with a specified number of threads.
0144   /**
0145    * Construct with a service maker, to create an initial set of services that
0146    * will be installed into the execution context at construction time.
0147    *
0148    * @param a An allocator that will be used for allocating objects that are
0149    * associated with the execution context, such as services and internal state
0150    * for I/O objects.
0151    *
0152    * @param num_threads The number of threads required.
0153    *
0154    * @param initial_services Used to create the initial services. The @c make
0155    * function will be called once at the end of execution_context construction.
0156    */
0157   template <typename Allocator>
0158   thread_pool(allocator_arg_t, const Allocator& a, std::size_t num_threads,
0159       const execution_context::service_maker& initial_services);
0160 
0161   /// Destructor.
0162   /**
0163    * Automatically stops and joins the pool, if not explicitly done beforehand.
0164    */
0165   BOOST_ASIO_DECL ~thread_pool();
0166 
0167   /// Obtains the executor associated with the pool.
0168   executor_type get_executor() noexcept;
0169 
0170   /// Obtains the executor associated with the pool.
0171   executor_type executor() noexcept;
0172 
0173   /// Stops the threads.
0174   /**
0175    * This function stops the threads as soon as possible. As a result of calling
0176    * @c stop(), pending function objects may be never be invoked.
0177    */
0178   BOOST_ASIO_DECL void stop();
0179 
0180   /// Attaches the current thread to the pool.
0181   /**
0182    * This function attaches the current thread to the pool so that it may be
0183    * used for executing submitted function objects. Blocks the calling thread
0184    * until the pool is stopped or joined and has no outstanding work.
0185    */
0186   BOOST_ASIO_DECL void attach();
0187 
0188   /// Joins the threads.
0189   /**
0190    * This function blocks until the threads in the pool have completed. If @c
0191    * stop() is not called prior to @c join(), the @c join() call will wait
0192    * until the pool has no more outstanding work.
0193    */
0194   BOOST_ASIO_DECL void join();
0195 
0196   /// Waits for threads to complete.
0197   /**
0198    * This function blocks until the threads in the pool have completed. If @c
0199    * stop() is not called prior to @c wait(), the @c wait() call will wait
0200    * until the pool has no more outstanding work.
0201    *
0202    * @note @c wait() is synonymous with @c join().
0203    */
0204   BOOST_ASIO_DECL void wait();
0205 
0206 private:
0207   thread_pool(const thread_pool&) = delete;
0208   thread_pool& operator=(const thread_pool&) = delete;
0209 
0210   struct thread_function;
0211 
0212 #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0213   // Helper function to calculate the default number of threads in the pool.
0214   BOOST_ASIO_DECL static long default_thread_pool_size();
0215 #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0216 
0217   // Helper function to ensure the thread pool size is not out of range.
0218   BOOST_ASIO_DECL static long clamp_thread_pool_size(std::size_t n);
0219 
0220   // Helper function to start all threads in the pool.
0221   BOOST_ASIO_DECL void start();
0222 
0223   // The underlying scheduler.
0224   detail::scheduler& scheduler_;
0225 
0226   // The threads in the pool.
0227   detail::thread_group<allocator<void>> threads_;
0228 
0229   // The current number of threads in the pool.
0230   detail::atomic_count num_threads_;
0231 
0232   // Whether a join call will have any effect.
0233   bool joinable_;
0234 };
0235 
0236 /// Executor implementation type used to submit functions to a thread pool.
0237 template <typename Allocator, unsigned int Bits>
0238 class thread_pool::basic_executor_type : detail::thread_pool_bits
0239 {
0240 public:
0241   /// Copy constructor.
0242   basic_executor_type(const basic_executor_type& other) noexcept
0243     : pool_(other.pool_),
0244       allocator_(other.allocator_),
0245       bits_(other.bits_)
0246   {
0247     if (Bits & outstanding_work_tracked)
0248       if (pool_)
0249         pool_->scheduler_.work_started();
0250   }
0251 
0252   /// Move constructor.
0253   basic_executor_type(basic_executor_type&& other) noexcept
0254     : pool_(other.pool_),
0255       allocator_(static_cast<Allocator&&>(other.allocator_)),
0256       bits_(other.bits_)
0257   {
0258     if (Bits & outstanding_work_tracked)
0259       other.pool_ = 0;
0260   }
0261 
0262   /// Destructor.
0263   ~basic_executor_type() noexcept
0264   {
0265     if (Bits & outstanding_work_tracked)
0266       if (pool_)
0267         pool_->scheduler_.work_finished();
0268   }
0269 
0270   /// Assignment operator.
0271   basic_executor_type& operator=(const basic_executor_type& other) noexcept;
0272 
0273   /// Move assignment operator.
0274   basic_executor_type& operator=(basic_executor_type&& other) noexcept;
0275 
0276 #if !defined(GENERATING_DOCUMENTATION)
0277 private:
0278   friend struct boost_asio_require_fn::impl;
0279   friend struct boost_asio_prefer_fn::impl;
0280 #endif // !defined(GENERATING_DOCUMENTATION)
0281 
0282   /// Obtain an executor with the @c blocking.possibly property.
0283   /**
0284    * Do not call this function directly. It is intended for use with the
0285    * boost::asio::require customisation point.
0286    *
0287    * For example:
0288    * @code auto ex1 = my_thread_pool.executor();
0289    * auto ex2 = boost::asio::require(ex1,
0290    *     boost::asio::execution::blocking.possibly); @endcode
0291    */
0292   constexpr basic_executor_type<Allocator,
0293       BOOST_ASIO_UNSPECIFIED(Bits & ~blocking_mask)>
0294   require(execution::blocking_t::possibly_t) const
0295   {
0296     return basic_executor_type<Allocator, Bits & ~blocking_mask>(
0297         pool_, allocator_, bits_ & ~blocking_mask);
0298   }
0299 
0300   /// Obtain an executor with the @c blocking.always property.
0301   /**
0302    * Do not call this function directly. It is intended for use with the
0303    * boost::asio::require customisation point.
0304    *
0305    * For example:
0306    * @code auto ex1 = my_thread_pool.executor();
0307    * auto ex2 = boost::asio::require(ex1,
0308    *     boost::asio::execution::blocking.always); @endcode
0309    */
0310   constexpr basic_executor_type<Allocator,
0311       BOOST_ASIO_UNSPECIFIED((Bits & ~blocking_mask) | blocking_always)>
0312   require(execution::blocking_t::always_t) const
0313   {
0314     return basic_executor_type<Allocator,
0315         BOOST_ASIO_UNSPECIFIED((Bits & ~blocking_mask) | blocking_always)>(
0316           pool_, allocator_, bits_ & ~blocking_mask);
0317   }
0318 
0319   /// Obtain an executor with the @c blocking.never property.
0320   /**
0321    * Do not call this function directly. It is intended for use with the
0322    * boost::asio::require customisation point.
0323    *
0324    * For example:
0325    * @code auto ex1 = my_thread_pool.executor();
0326    * auto ex2 = boost::asio::require(ex1,
0327    *     boost::asio::execution::blocking.never); @endcode
0328    */
0329   constexpr basic_executor_type<Allocator,
0330       BOOST_ASIO_UNSPECIFIED(Bits & ~blocking_mask)>
0331   require(execution::blocking_t::never_t) const
0332   {
0333     return basic_executor_type<Allocator, Bits & ~blocking_mask>(
0334         pool_, allocator_, (bits_ & ~blocking_mask) | blocking_never);
0335   }
0336 
0337   /// Obtain an executor with the @c relationship.fork property.
0338   /**
0339    * Do not call this function directly. It is intended for use with the
0340    * boost::asio::require customisation point.
0341    *
0342    * For example:
0343    * @code auto ex1 = my_thread_pool.executor();
0344    * auto ex2 = boost::asio::require(ex1,
0345    *     boost::asio::execution::relationship.fork); @endcode
0346    */
0347   constexpr basic_executor_type require(execution::relationship_t::fork_t) const
0348   {
0349     return basic_executor_type(pool_,
0350         allocator_, bits_ & ~relationship_continuation);
0351   }
0352 
0353   /// Obtain an executor with the @c relationship.continuation property.
0354   /**
0355    * Do not call this function directly. It is intended for use with the
0356    * boost::asio::require customisation point.
0357    *
0358    * For example:
0359    * @code auto ex1 = my_thread_pool.executor();
0360    * auto ex2 = boost::asio::require(ex1,
0361    *     boost::asio::execution::relationship.continuation); @endcode
0362    */
0363   constexpr basic_executor_type require(
0364       execution::relationship_t::continuation_t) const
0365   {
0366     return basic_executor_type(pool_,
0367         allocator_, bits_ | relationship_continuation);
0368   }
0369 
0370   /// Obtain an executor with the @c outstanding_work.tracked property.
0371   /**
0372    * Do not call this function directly. It is intended for use with the
0373    * boost::asio::require customisation point.
0374    *
0375    * For example:
0376    * @code auto ex1 = my_thread_pool.executor();
0377    * auto ex2 = boost::asio::require(ex1,
0378    *     boost::asio::execution::outstanding_work.tracked); @endcode
0379    */
0380   constexpr basic_executor_type<Allocator,
0381       BOOST_ASIO_UNSPECIFIED(Bits | outstanding_work_tracked)>
0382   require(execution::outstanding_work_t::tracked_t) const
0383   {
0384     return basic_executor_type<Allocator, Bits | outstanding_work_tracked>(
0385         pool_, allocator_, bits_);
0386   }
0387 
0388   /// Obtain an executor with the @c outstanding_work.untracked property.
0389   /**
0390    * Do not call this function directly. It is intended for use with the
0391    * boost::asio::require customisation point.
0392    *
0393    * For example:
0394    * @code auto ex1 = my_thread_pool.executor();
0395    * auto ex2 = boost::asio::require(ex1,
0396    *     boost::asio::execution::outstanding_work.untracked); @endcode
0397    */
0398   constexpr basic_executor_type<Allocator,
0399       BOOST_ASIO_UNSPECIFIED(Bits & ~outstanding_work_tracked)>
0400   require(execution::outstanding_work_t::untracked_t) const
0401   {
0402     return basic_executor_type<Allocator, Bits & ~outstanding_work_tracked>(
0403         pool_, allocator_, bits_);
0404   }
0405 
0406   /// Obtain an executor with the specified @c allocator property.
0407   /**
0408    * Do not call this function directly. It is intended for use with the
0409    * boost::asio::require customisation point.
0410    *
0411    * For example:
0412    * @code auto ex1 = my_thread_pool.executor();
0413    * auto ex2 = boost::asio::require(ex1,
0414    *     boost::asio::execution::allocator(my_allocator)); @endcode
0415    */
0416   template <typename OtherAllocator>
0417   constexpr basic_executor_type<OtherAllocator, Bits>
0418   require(execution::allocator_t<OtherAllocator> a) const
0419   {
0420     return basic_executor_type<OtherAllocator, Bits>(
0421         pool_, a.value(), bits_);
0422   }
0423 
0424   /// Obtain an executor with the default @c allocator property.
0425   /**
0426    * Do not call this function directly. It is intended for use with the
0427    * boost::asio::require customisation point.
0428    *
0429    * For example:
0430    * @code auto ex1 = my_thread_pool.executor();
0431    * auto ex2 = boost::asio::require(ex1,
0432    *     boost::asio::execution::allocator); @endcode
0433    */
0434   constexpr basic_executor_type<std::allocator<void>, Bits>
0435   require(execution::allocator_t<void>) const
0436   {
0437     return basic_executor_type<std::allocator<void>, Bits>(
0438         pool_, std::allocator<void>(), bits_);
0439   }
0440 
0441 #if !defined(GENERATING_DOCUMENTATION)
0442 private:
0443   friend struct boost_asio_query_fn::impl;
0444   friend struct boost::asio::execution::detail::mapping_t<0>;
0445   friend struct boost::asio::execution::detail::inline_exception_handling_t<0>;
0446   friend struct boost::asio::execution::detail::outstanding_work_t<0>;
0447 #endif // !defined(GENERATING_DOCUMENTATION)
0448 
0449   /// Query the current value of the @c mapping property.
0450   /**
0451    * Do not call this function directly. It is intended for use with the
0452    * boost::asio::query customisation point.
0453    *
0454    * For example:
0455    * @code auto ex = my_thread_pool.executor();
0456    * if (boost::asio::query(ex, boost::asio::execution::mapping)
0457    *       == boost::asio::execution::mapping.thread)
0458    *   ... @endcode
0459    */
0460   static constexpr execution::mapping_t query(execution::mapping_t) noexcept
0461   {
0462     return execution::mapping.thread;
0463   }
0464 
0465   /// Query the current value of the @c inline_exception_handling property.
0466   /**
0467    * Do not call this function directly. It is intended for use with the
0468    * boost::asio::query customisation point.
0469    *
0470    * For example:
0471    * @code auto ex = my_thread_pool.get_executor();
0472    * if (boost::asio::query(ex,
0473    *       boost::asio::execution::inline_exception_handling)
0474    *     == boost::asio::execution::inline_exception_handling.terminate)
0475    *   ... @endcode
0476    */
0477   static constexpr execution::inline_exception_handling_t query(
0478       execution::inline_exception_handling_t) noexcept
0479   {
0480     return execution::inline_exception_handling.terminate;
0481   }
0482 
0483   /// Query the current value of the @c context property.
0484   /**
0485    * Do not call this function directly. It is intended for use with the
0486    * boost::asio::query customisation point.
0487    *
0488    * For example:
0489    * @code auto ex = my_thread_pool.executor();
0490    * boost::asio::thread_pool& pool = boost::asio::query(
0491    *     ex, boost::asio::execution::context); @endcode
0492    */
0493   thread_pool& query(execution::context_t) const noexcept
0494   {
0495     return *pool_;
0496   }
0497 
0498   /// Query the current value of the @c blocking property.
0499   /**
0500    * Do not call this function directly. It is intended for use with the
0501    * boost::asio::query customisation point.
0502    *
0503    * For example:
0504    * @code auto ex = my_thread_pool.executor();
0505    * if (boost::asio::query(ex, boost::asio::execution::blocking)
0506    *       == boost::asio::execution::blocking.always)
0507    *   ... @endcode
0508    */
0509   constexpr execution::blocking_t query(execution::blocking_t) const noexcept
0510   {
0511     return (bits_ & blocking_never)
0512       ? execution::blocking_t(execution::blocking.never)
0513       : ((Bits & blocking_always)
0514           ? execution::blocking_t(execution::blocking.always)
0515           : execution::blocking_t(execution::blocking.possibly));
0516   }
0517 
0518   /// Query the current value of the @c relationship property.
0519   /**
0520    * Do not call this function directly. It is intended for use with the
0521    * boost::asio::query customisation point.
0522    *
0523    * For example:
0524    * @code auto ex = my_thread_pool.executor();
0525    * if (boost::asio::query(ex, boost::asio::execution::relationship)
0526    *       == boost::asio::execution::relationship.continuation)
0527    *   ... @endcode
0528    */
0529   constexpr execution::relationship_t query(
0530       execution::relationship_t) const noexcept
0531   {
0532     return (bits_ & relationship_continuation)
0533       ? execution::relationship_t(execution::relationship.continuation)
0534       : execution::relationship_t(execution::relationship.fork);
0535   }
0536 
0537   /// Query the current value of the @c outstanding_work property.
0538   /**
0539    * Do not call this function directly. It is intended for use with the
0540    * boost::asio::query customisation point.
0541    *
0542    * For example:
0543    * @code auto ex = my_thread_pool.executor();
0544    * if (boost::asio::query(ex, boost::asio::execution::outstanding_work)
0545    *       == boost::asio::execution::outstanding_work.tracked)
0546    *   ... @endcode
0547    */
0548   static constexpr execution::outstanding_work_t query(
0549       execution::outstanding_work_t) noexcept
0550   {
0551     return (Bits & outstanding_work_tracked)
0552       ? execution::outstanding_work_t(execution::outstanding_work.tracked)
0553       : execution::outstanding_work_t(execution::outstanding_work.untracked);
0554   }
0555 
0556   /// Query the current value of the @c allocator property.
0557   /**
0558    * Do not call this function directly. It is intended for use with the
0559    * boost::asio::query customisation point.
0560    *
0561    * For example:
0562    * @code auto ex = my_thread_pool.executor();
0563    * auto alloc = boost::asio::query(ex,
0564    *     boost::asio::execution::allocator); @endcode
0565    */
0566   template <typename OtherAllocator>
0567   constexpr Allocator query(
0568       execution::allocator_t<OtherAllocator>) const noexcept
0569   {
0570     return allocator_;
0571   }
0572 
0573   /// Query the current value of the @c allocator property.
0574   /**
0575    * Do not call this function directly. It is intended for use with the
0576    * boost::asio::query customisation point.
0577    *
0578    * For example:
0579    * @code auto ex = my_thread_pool.executor();
0580    * auto alloc = boost::asio::query(ex,
0581    *     boost::asio::execution::allocator); @endcode
0582    */
0583   constexpr Allocator query(execution::allocator_t<void>) const noexcept
0584   {
0585     return allocator_;
0586   }
0587 
0588   /// Query the occupancy (recommended number of work items) for the pool.
0589   /**
0590    * Do not call this function directly. It is intended for use with the
0591    * boost::asio::query customisation point.
0592    *
0593    * For example:
0594    * @code auto ex = my_thread_pool.executor();
0595    * std::size_t occupancy = boost::asio::query(
0596    *     ex, boost::asio::execution::occupancy); @endcode
0597    */
0598   std::size_t query(execution::occupancy_t) const noexcept
0599   {
0600     return static_cast<std::size_t>(pool_->num_threads_);
0601   }
0602 
0603 public:
0604   /// Determine whether the thread pool is running in the current thread.
0605   /**
0606    * @return @c true if the current thread is running the thread pool. Otherwise
0607    * returns @c false.
0608    */
0609   bool running_in_this_thread() const noexcept;
0610 
0611   /// Compare two executors for equality.
0612   /**
0613    * Two executors are equal if they refer to the same underlying thread pool.
0614    */
0615   friend bool operator==(const basic_executor_type& a,
0616       const basic_executor_type& b) noexcept
0617   {
0618     return a.pool_ == b.pool_
0619       && a.allocator_ == b.allocator_
0620       && a.bits_ == b.bits_;
0621   }
0622 
0623   /// Compare two executors for inequality.
0624   /**
0625    * Two executors are equal if they refer to the same underlying thread pool.
0626    */
0627   friend bool operator!=(const basic_executor_type& a,
0628       const basic_executor_type& b) noexcept
0629   {
0630     return a.pool_ != b.pool_
0631       || a.allocator_ != b.allocator_
0632       || a.bits_ != b.bits_;
0633   }
0634 
0635   /// Execution function.
0636   template <typename Function>
0637   void execute(Function&& f) const
0638   {
0639     this->do_execute(static_cast<Function&&>(f),
0640         integral_constant<bool, (Bits & blocking_always) != 0>());
0641   }
0642 
0643 public:
0644 #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0645   /// Obtain the underlying execution context.
0646   thread_pool& context() const noexcept;
0647 
0648   /// Inform the thread pool that it has some outstanding work to do.
0649   /**
0650    * This function is used to inform the thread pool that some work has begun.
0651    * This ensures that the thread pool's join() function will not return while
0652    * the work is underway.
0653    */
0654   void on_work_started() const noexcept;
0655 
0656   /// Inform the thread pool that some work is no longer outstanding.
0657   /**
0658    * This function is used to inform the thread pool that some work has
0659    * finished. Once the count of unfinished work reaches zero, the thread
0660    * pool's join() function is permitted to exit.
0661    */
0662   void on_work_finished() const noexcept;
0663 
0664   /// Request the thread pool to invoke the given function object.
0665   /**
0666    * This function is used to ask the thread pool to execute the given function
0667    * object. If the current thread belongs to the pool, @c dispatch() executes
0668    * the function before returning. Otherwise, the function will be scheduled
0669    * to run on the thread pool.
0670    *
0671    * @param f The function object to be called. The executor will make
0672    * a copy of the handler object as required. The function signature of the
0673    * function object must be: @code void function(); @endcode
0674    *
0675    * @param a An allocator that may be used by the executor to allocate the
0676    * internal storage needed for function invocation.
0677    */
0678   template <typename Function, typename OtherAllocator>
0679   void dispatch(Function&& f, const OtherAllocator& a) const;
0680 
0681   /// Request the thread pool to invoke the given function object.
0682   /**
0683    * This function is used to ask the thread pool to execute the given function
0684    * object. The function object will never be executed inside @c post().
0685    * Instead, it will be scheduled to run on the thread pool.
0686    *
0687    * @param f The function object to be called. The executor will make
0688    * a copy of the handler object as required. The function signature of the
0689    * function object must be: @code void function(); @endcode
0690    *
0691    * @param a An allocator that may be used by the executor to allocate the
0692    * internal storage needed for function invocation.
0693    */
0694   template <typename Function, typename OtherAllocator>
0695   void post(Function&& f, const OtherAllocator& a) const;
0696 
0697   /// Request the thread pool to invoke the given function object.
0698   /**
0699    * This function is used to ask the thread pool to execute the given function
0700    * object. The function object will never be executed inside @c defer().
0701    * Instead, it will be scheduled to run on the thread pool.
0702    *
0703    * If the current thread belongs to the thread pool, @c defer() will delay
0704    * scheduling the function object until the current thread returns control to
0705    * the pool.
0706    *
0707    * @param f The function object to be called. The executor will make
0708    * a copy of the handler object as required. The function signature of the
0709    * function object must be: @code void function(); @endcode
0710    *
0711    * @param a An allocator that may be used by the executor to allocate the
0712    * internal storage needed for function invocation.
0713    */
0714   template <typename Function, typename OtherAllocator>
0715   void defer(Function&& f, const OtherAllocator& a) const;
0716 #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0717 
0718 private:
0719   friend class thread_pool;
0720   template <typename, unsigned int> friend class basic_executor_type;
0721 
0722   // Constructor used by thread_pool::get_executor().
0723   explicit basic_executor_type(thread_pool& p) noexcept
0724     : pool_(&p),
0725       allocator_(),
0726       bits_(0)
0727   {
0728     if (Bits & outstanding_work_tracked)
0729       pool_->scheduler_.work_started();
0730   }
0731 
0732   // Constructor used by require().
0733   basic_executor_type(thread_pool* p,
0734       const Allocator& a, unsigned int bits) noexcept
0735     : pool_(p),
0736       allocator_(a),
0737       bits_(bits)
0738   {
0739     if (Bits & outstanding_work_tracked)
0740       if (pool_)
0741         pool_->scheduler_.work_started();
0742   }
0743 
0744   /// Execution helper implementation for possibly and never blocking.
0745   template <typename Function>
0746   void do_execute(Function&& f, false_type) const;
0747 
0748   /// Execution helper implementation for always blocking.
0749   template <typename Function>
0750   void do_execute(Function&& f, true_type) const;
0751 
0752   // The underlying thread pool.
0753   thread_pool* pool_;
0754 
0755   // The allocator used for execution functions.
0756   Allocator allocator_;
0757 
0758   // The runtime-switched properties of the thread pool executor.
0759   unsigned int bits_;
0760 };
0761 
0762 #if !defined(GENERATING_DOCUMENTATION)
0763 
0764 namespace traits {
0765 
0766 #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
0767 
0768 template <typename Allocator, unsigned int Bits>
0769 struct equality_comparable<
0770     boost::asio::thread_pool::basic_executor_type<Allocator, Bits>
0771   >
0772 {
0773   static constexpr bool is_valid = true;
0774   static constexpr bool is_noexcept = true;
0775 };
0776 
0777 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
0778 
0779 #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
0780 
0781 template <typename Allocator, unsigned int Bits, typename Function>
0782 struct execute_member<
0783     boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
0784     Function
0785   >
0786 {
0787   static constexpr bool is_valid = true;
0788   static constexpr bool is_noexcept = false;
0789   typedef void result_type;
0790 };
0791 
0792 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
0793 
0794 #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
0795 
0796 template <typename Allocator, unsigned int Bits>
0797 struct require_member<
0798     boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
0799     boost::asio::execution::blocking_t::possibly_t
0800   > : boost::asio::detail::thread_pool_bits
0801 {
0802   static constexpr bool is_valid = true;
0803   static constexpr bool is_noexcept = true;
0804   typedef boost::asio::thread_pool::basic_executor_type<
0805       Allocator, Bits & ~blocking_mask> result_type;
0806 };
0807 
0808 template <typename Allocator, unsigned int Bits>
0809 struct require_member<
0810     boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
0811     boost::asio::execution::blocking_t::always_t
0812   > : boost::asio::detail::thread_pool_bits
0813 {
0814   static constexpr bool is_valid = true;
0815   static constexpr bool is_noexcept = false;
0816   typedef boost::asio::thread_pool::basic_executor_type<Allocator,
0817       (Bits & ~blocking_mask) | blocking_always> result_type;
0818 };
0819 
0820 template <typename Allocator, unsigned int Bits>
0821 struct require_member<
0822     boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
0823     boost::asio::execution::blocking_t::never_t
0824   > : boost::asio::detail::thread_pool_bits
0825 {
0826   static constexpr bool is_valid = true;
0827   static constexpr bool is_noexcept = false;
0828   typedef boost::asio::thread_pool::basic_executor_type<
0829       Allocator, Bits & ~blocking_mask> result_type;
0830 };
0831 
0832 template <typename Allocator, unsigned int Bits>
0833 struct require_member<
0834     boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
0835     boost::asio::execution::relationship_t::fork_t
0836   >
0837 {
0838   static constexpr bool is_valid = true;
0839   static constexpr bool is_noexcept = false;
0840   typedef boost::asio::thread_pool::basic_executor_type<
0841       Allocator, Bits> result_type;
0842 };
0843 
0844 template <typename Allocator, unsigned int Bits>
0845 struct require_member<
0846     boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
0847     boost::asio::execution::relationship_t::continuation_t
0848   >
0849 {
0850   static constexpr bool is_valid = true;
0851   static constexpr bool is_noexcept = false;
0852   typedef boost::asio::thread_pool::basic_executor_type<
0853       Allocator, Bits> result_type;
0854 };
0855 
0856 template <typename Allocator, unsigned int Bits>
0857 struct require_member<
0858     boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
0859     boost::asio::execution::outstanding_work_t::tracked_t
0860   > : boost::asio::detail::thread_pool_bits
0861 {
0862   static constexpr bool is_valid = true;
0863   static constexpr bool is_noexcept = false;
0864   typedef boost::asio::thread_pool::basic_executor_type<
0865       Allocator, Bits | outstanding_work_tracked> result_type;
0866 };
0867 
0868 template <typename Allocator, unsigned int Bits>
0869 struct require_member<
0870     boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
0871     boost::asio::execution::outstanding_work_t::untracked_t
0872   > : boost::asio::detail::thread_pool_bits
0873 {
0874   static constexpr bool is_valid = true;
0875   static constexpr bool is_noexcept = false;
0876   typedef boost::asio::thread_pool::basic_executor_type<
0877       Allocator, Bits & ~outstanding_work_tracked> result_type;
0878 };
0879 
0880 template <typename Allocator, unsigned int Bits>
0881 struct require_member<
0882     boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
0883     boost::asio::execution::allocator_t<void>
0884   >
0885 {
0886   static constexpr bool is_valid = true;
0887   static constexpr bool is_noexcept = false;
0888   typedef boost::asio::thread_pool::basic_executor_type<
0889       std::allocator<void>, Bits> result_type;
0890 };
0891 
0892 template <unsigned int Bits,
0893     typename Allocator, typename OtherAllocator>
0894 struct require_member<
0895     boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
0896     boost::asio::execution::allocator_t<OtherAllocator>
0897   >
0898 {
0899   static constexpr bool is_valid = true;
0900   static constexpr bool is_noexcept = false;
0901   typedef boost::asio::thread_pool::basic_executor_type<
0902       OtherAllocator, Bits> result_type;
0903 };
0904 
0905 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
0906 
0907 #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
0908 
0909 template <typename Allocator, unsigned int Bits, typename Property>
0910 struct query_static_constexpr_member<
0911     boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
0912     Property,
0913     typename boost::asio::enable_if<
0914       boost::asio::is_convertible<
0915         Property,
0916         boost::asio::execution::outstanding_work_t
0917       >::value
0918     >::type
0919   > : boost::asio::detail::thread_pool_bits
0920 {
0921   static constexpr bool is_valid = true;
0922   static constexpr bool is_noexcept = true;
0923   typedef boost::asio::execution::outstanding_work_t result_type;
0924 
0925   static constexpr result_type value() noexcept
0926   {
0927     return (Bits & outstanding_work_tracked)
0928       ? execution::outstanding_work_t(execution::outstanding_work.tracked)
0929       : execution::outstanding_work_t(execution::outstanding_work.untracked);
0930   }
0931 };
0932 
0933 template <typename Allocator, unsigned int Bits, typename Property>
0934 struct query_static_constexpr_member<
0935     boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
0936     Property,
0937     typename boost::asio::enable_if<
0938       boost::asio::is_convertible<
0939         Property,
0940         boost::asio::execution::mapping_t
0941       >::value
0942     >::type
0943   >
0944 {
0945   static constexpr bool is_valid = true;
0946   static constexpr bool is_noexcept = true;
0947   typedef boost::asio::execution::mapping_t::thread_t result_type;
0948 
0949   static constexpr result_type value() noexcept
0950   {
0951     return result_type();
0952   }
0953 };
0954 
0955 template <typename Allocator, unsigned int Bits, typename Property>
0956 struct query_static_constexpr_member<
0957     boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
0958     Property,
0959     typename boost::asio::enable_if<
0960       boost::asio::is_convertible<
0961         Property,
0962         boost::asio::execution::inline_exception_handling_t
0963       >::value
0964     >::type
0965   >
0966 {
0967   static constexpr bool is_valid = true;
0968   static constexpr bool is_noexcept = true;
0969   typedef boost::asio::execution::inline_exception_handling_t::terminate_t
0970     result_type;
0971 
0972   static constexpr result_type value() noexcept
0973   {
0974     return result_type();
0975   }
0976 };
0977 
0978 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
0979 
0980 #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
0981 
0982 template <typename Allocator, unsigned int Bits, typename Property>
0983 struct query_member<
0984     boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
0985     Property,
0986     typename boost::asio::enable_if<
0987       boost::asio::is_convertible<
0988         Property,
0989         boost::asio::execution::blocking_t
0990       >::value
0991     >::type
0992   >
0993 {
0994   static constexpr bool is_valid = true;
0995   static constexpr bool is_noexcept = true;
0996   typedef boost::asio::execution::blocking_t result_type;
0997 };
0998 
0999 template <typename Allocator, unsigned int Bits, typename Property>
1000 struct query_member<
1001     boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
1002     Property,
1003     typename boost::asio::enable_if<
1004       boost::asio::is_convertible<
1005         Property,
1006         boost::asio::execution::relationship_t
1007       >::value
1008     >::type
1009   >
1010 {
1011   static constexpr bool is_valid = true;
1012   static constexpr bool is_noexcept = true;
1013   typedef boost::asio::execution::relationship_t result_type;
1014 };
1015 
1016 template <typename Allocator, unsigned int Bits>
1017 struct query_member<
1018     boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
1019     boost::asio::execution::occupancy_t
1020   >
1021 {
1022   static constexpr bool is_valid = true;
1023   static constexpr bool is_noexcept = true;
1024   typedef std::size_t result_type;
1025 };
1026 
1027 template <typename Allocator, unsigned int Bits>
1028 struct query_member<
1029     boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
1030     boost::asio::execution::context_t
1031   >
1032 {
1033   static constexpr bool is_valid = true;
1034   static constexpr bool is_noexcept = true;
1035   typedef boost::asio::thread_pool& result_type;
1036 };
1037 
1038 template <typename Allocator, unsigned int Bits>
1039 struct query_member<
1040     boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
1041     boost::asio::execution::allocator_t<void>
1042   >
1043 {
1044   static constexpr bool is_valid = true;
1045   static constexpr bool is_noexcept = true;
1046   typedef Allocator result_type;
1047 };
1048 
1049 template <typename Allocator, unsigned int Bits, typename OtherAllocator>
1050 struct query_member<
1051     boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
1052     boost::asio::execution::allocator_t<OtherAllocator>
1053   >
1054 {
1055   static constexpr bool is_valid = true;
1056   static constexpr bool is_noexcept = true;
1057   typedef Allocator result_type;
1058 };
1059 
1060 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
1061 
1062 } // namespace traits
1063 
1064 namespace execution {
1065 
1066 template <>
1067 struct is_executor<thread_pool> : false_type
1068 {
1069 };
1070 
1071 } // namespace execution
1072 
1073 #endif // !defined(GENERATING_DOCUMENTATION)
1074 
1075 } // namespace asio
1076 } // namespace boost
1077 
1078 #include <boost/asio/detail/pop_options.hpp>
1079 
1080 #include <boost/asio/impl/thread_pool.hpp>
1081 #if defined(BOOST_ASIO_HEADER_ONLY)
1082 # include <boost/asio/impl/thread_pool.ipp>
1083 #endif // defined(BOOST_ASIO_HEADER_ONLY)
1084 
1085 #endif // BOOST_ASIO_THREAD_POOL_HPP