Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:29:12

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