Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 08:35:42

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