]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/asio/thread_pool.hpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / boost / asio / thread_pool.hpp
CommitLineData
b32b8144
FG
1//
2// thread_pool.hpp
3// ~~~~~~~~~~~~~~~
4//
f67539c2 5// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
b32b8144
FG
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_THREAD_POOL_HPP
12#define BOOST_ASIO_THREAD_POOL_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <boost/asio/detail/config.hpp>
20effc67 19#include <boost/asio/detail/atomic_count.hpp>
b32b8144
FG
20#include <boost/asio/detail/scheduler.hpp>
21#include <boost/asio/detail/thread_group.hpp>
20effc67 22#include <boost/asio/execution.hpp>
b32b8144
FG
23#include <boost/asio/execution_context.hpp>
24
25#include <boost/asio/detail/push_options.hpp>
26
27namespace boost {
28namespace asio {
20effc67
TL
29namespace detail {
30 struct thread_pool_bits
31 {
32 BOOST_ASIO_STATIC_CONSTEXPR(unsigned int, blocking_never = 1);
33 BOOST_ASIO_STATIC_CONSTEXPR(unsigned int, blocking_always = 2);
34 BOOST_ASIO_STATIC_CONSTEXPR(unsigned int, blocking_mask = 3);
35 BOOST_ASIO_STATIC_CONSTEXPR(unsigned int, relationship_continuation = 4);
36 BOOST_ASIO_STATIC_CONSTEXPR(unsigned int, outstanding_work_tracked = 8);
37 };
38} // namespace detail
b32b8144
FG
39
40/// A simple fixed-size thread pool.
41/**
42 * The thread pool class is an execution context where functions are permitted
43 * to run on one of a fixed number of threads.
44 *
45 * @par Submitting tasks to the pool
46 *
20effc67 47 * To submit functions to the thread pool, use the @ref boost::asio::dispatch,
b32b8144
FG
48 * @ref boost::asio::post or @ref boost::asio::defer free functions.
49 *
50 * For example:
51 *
52 * @code void my_task()
53 * {
54 * ...
55 * }
56 *
57 * ...
58 *
59 * // Launch the pool with four threads.
60 * boost::asio::thread_pool pool(4);
61 *
62 * // Submit a function to the pool.
63 * boost::asio::post(pool, my_task);
64 *
65 * // Submit a lambda object to the pool.
66 * boost::asio::post(pool,
67 * []()
68 * {
69 * ...
70 * });
71 *
72 * // Wait for all tasks in the pool to complete.
73 * pool.join(); @endcode
74 */
75class thread_pool
76 : public execution_context
77{
78public:
20effc67
TL
79 template <typename Allocator, unsigned int Bits>
80 class basic_executor_type;
81
82 template <typename Allocator, unsigned int Bits>
83 friend class basic_executor_type;
84
85 /// Executor used to submit functions to a thread pool.
86 typedef basic_executor_type<std::allocator<void>, 0> executor_type;
b32b8144 87
20effc67
TL
88 /// Scheduler used to schedule receivers on a thread pool.
89 typedef basic_executor_type<std::allocator<void>, 0> scheduler_type;
90
91#if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
b32b8144
FG
92 /// Constructs a pool with an automatically determined number of threads.
93 BOOST_ASIO_DECL thread_pool();
20effc67 94#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
b32b8144
FG
95
96 /// Constructs a pool with a specified number of threads.
97 BOOST_ASIO_DECL thread_pool(std::size_t num_threads);
98
99 /// Destructor.
100 /**
101 * Automatically stops and joins the pool, if not explicitly done beforehand.
102 */
103 BOOST_ASIO_DECL ~thread_pool();
104
105 /// Obtains the executor associated with the pool.
106 executor_type get_executor() BOOST_ASIO_NOEXCEPT;
107
20effc67
TL
108 /// Obtains the executor associated with the pool.
109 executor_type executor() BOOST_ASIO_NOEXCEPT;
110
111 /// Obtains the scheduler associated with the pool.
112 scheduler_type scheduler() BOOST_ASIO_NOEXCEPT;
113
b32b8144
FG
114 /// Stops the threads.
115 /**
116 * This function stops the threads as soon as possible. As a result of calling
117 * @c stop(), pending function objects may be never be invoked.
118 */
119 BOOST_ASIO_DECL void stop();
120
20effc67
TL
121 /// Attaches the current thread to the pool.
122 /**
123 * This function attaches the current thread to the pool so that it may be
124 * used for executing submitted function objects. Blocks the calling thread
125 * until the pool is stopped or joined and has no outstanding work.
126 */
127 BOOST_ASIO_DECL void attach();
128
b32b8144
FG
129 /// Joins the threads.
130 /**
131 * This function blocks until the threads in the pool have completed. If @c
132 * stop() is not called prior to @c join(), the @c join() call will wait
133 * until the pool has no more outstanding work.
134 */
135 BOOST_ASIO_DECL void join();
136
20effc67
TL
137 /// Waits for threads to complete.
138 /**
139 * This function blocks until the threads in the pool have completed. If @c
140 * stop() is not called prior to @c wait(), the @c wait() call will wait
141 * until the pool has no more outstanding work.
142 */
143 BOOST_ASIO_DECL void wait();
144
b32b8144 145private:
20effc67
TL
146 thread_pool(const thread_pool&) BOOST_ASIO_DELETED;
147 thread_pool& operator=(const thread_pool&) BOOST_ASIO_DELETED;
148
b32b8144
FG
149 struct thread_function;
150
92f5a8d4
TL
151 // Helper function to create the underlying scheduler.
152 BOOST_ASIO_DECL detail::scheduler& add_scheduler(detail::scheduler* s);
153
b32b8144
FG
154 // The underlying scheduler.
155 detail::scheduler& scheduler_;
156
157 // The threads in the pool.
158 detail::thread_group threads_;
20effc67
TL
159
160 // The current number of threads in the pool.
161 detail::atomic_count num_threads_;
b32b8144
FG
162};
163
20effc67
TL
164/// Executor implementation type used to submit functions to a thread pool.
165template <typename Allocator, unsigned int Bits>
166class thread_pool::basic_executor_type : detail::thread_pool_bits
b32b8144
FG
167{
168public:
20effc67
TL
169 /// The sender type, when this type is used as a scheduler.
170 typedef basic_executor_type sender_type;
171
172 /// The bulk execution shape type.
173 typedef std::size_t shape_type;
174
175 /// The bulk execution index type.
176 typedef std::size_t index_type;
177
178#if defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_TYPED_SENDER_TRAIT) \
179 && defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR)
180 template <
181 template <typename...> class Tuple,
182 template <typename...> class Variant>
183 using value_types = Variant<Tuple<>>;
184
185 template <template <typename...> class Variant>
186 using error_types = Variant<std::exception_ptr>;
187
188 BOOST_ASIO_STATIC_CONSTEXPR(bool, sends_done = true);
189#endif // defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_TYPED_SENDER_TRAIT)
190 // && defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR)
191
192 /// Copy constructor.
193 basic_executor_type(
194 const basic_executor_type& other) BOOST_ASIO_NOEXCEPT
195 : pool_(other.pool_),
196 allocator_(other.allocator_),
197 bits_(other.bits_)
198 {
199 if (Bits & outstanding_work_tracked)
200 if (pool_)
201 pool_->scheduler_.work_started();
202 }
203
204#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
205 /// Move constructor.
206 basic_executor_type(basic_executor_type&& other) BOOST_ASIO_NOEXCEPT
207 : pool_(other.pool_),
208 allocator_(BOOST_ASIO_MOVE_CAST(Allocator)(other.allocator_)),
209 bits_(other.bits_)
210 {
211 if (Bits & outstanding_work_tracked)
212 other.pool_ = 0;
213 }
214#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
215
216 /// Destructor.
217 ~basic_executor_type() BOOST_ASIO_NOEXCEPT
218 {
219 if (Bits & outstanding_work_tracked)
220 if (pool_)
221 pool_->scheduler_.work_finished();
222 }
223
224 /// Assignment operator.
225 basic_executor_type& operator=(
226 const basic_executor_type& other) BOOST_ASIO_NOEXCEPT;
227
228#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
229 /// Move assignment operator.
230 basic_executor_type& operator=(
231 basic_executor_type&& other) BOOST_ASIO_NOEXCEPT;
232#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
233
234 /// Obtain an executor with the @c blocking.possibly property.
235 /**
236 * Do not call this function directly. It is intended for use with the
237 * boost::asio::require customisation point.
238 *
239 * For example:
240 * @code auto ex1 = my_thread_pool.executor();
241 * auto ex2 = boost::asio::require(ex1,
242 * boost::asio::execution::blocking.possibly); @endcode
243 */
244 BOOST_ASIO_CONSTEXPR basic_executor_type<Allocator,
245 BOOST_ASIO_UNSPECIFIED(Bits & ~blocking_mask)>
246 require(execution::blocking_t::possibly_t) const
247 {
248 return basic_executor_type<Allocator, Bits & ~blocking_mask>(
249 pool_, allocator_, bits_ & ~blocking_mask);
250 }
251
252 /// Obtain an executor with the @c blocking.always property.
253 /**
254 * Do not call this function directly. It is intended for use with the
255 * boost::asio::require customisation point.
256 *
257 * For example:
258 * @code auto ex1 = my_thread_pool.executor();
259 * auto ex2 = boost::asio::require(ex1,
260 * boost::asio::execution::blocking.always); @endcode
261 */
262 BOOST_ASIO_CONSTEXPR basic_executor_type<Allocator,
263 BOOST_ASIO_UNSPECIFIED((Bits & ~blocking_mask) | blocking_always)>
264 require(execution::blocking_t::always_t) const
265 {
266 return basic_executor_type<Allocator,
267 BOOST_ASIO_UNSPECIFIED((Bits & ~blocking_mask) | blocking_always)>(
268 pool_, allocator_, bits_ & ~blocking_mask);
269 }
270
271 /// Obtain an executor with the @c blocking.never property.
272 /**
273 * Do not call this function directly. It is intended for use with the
274 * boost::asio::require customisation point.
275 *
276 * For example:
277 * @code auto ex1 = my_thread_pool.executor();
278 * auto ex2 = boost::asio::require(ex1,
279 * boost::asio::execution::blocking.never); @endcode
280 */
281 BOOST_ASIO_CONSTEXPR basic_executor_type<Allocator,
282 BOOST_ASIO_UNSPECIFIED(Bits & ~blocking_mask)>
283 require(execution::blocking_t::never_t) const
284 {
285 return basic_executor_type<Allocator, Bits & ~blocking_mask>(
286 pool_, allocator_, (bits_ & ~blocking_mask) | blocking_never);
287 }
288
289 /// Obtain an executor with the @c relationship.fork property.
290 /**
291 * Do not call this function directly. It is intended for use with the
292 * boost::asio::require customisation point.
293 *
294 * For example:
295 * @code auto ex1 = my_thread_pool.executor();
296 * auto ex2 = boost::asio::require(ex1,
297 * boost::asio::execution::relationship.fork); @endcode
298 */
299 BOOST_ASIO_CONSTEXPR basic_executor_type require(
300 execution::relationship_t::fork_t) const
301 {
302 return basic_executor_type(pool_,
303 allocator_, bits_ & ~relationship_continuation);
304 }
305
306 /// Obtain an executor with the @c relationship.continuation property.
307 /**
308 * Do not call this function directly. It is intended for use with the
309 * boost::asio::require customisation point.
310 *
311 * For example:
312 * @code auto ex1 = my_thread_pool.executor();
313 * auto ex2 = boost::asio::require(ex1,
314 * boost::asio::execution::relationship.continuation); @endcode
315 */
316 BOOST_ASIO_CONSTEXPR basic_executor_type require(
317 execution::relationship_t::continuation_t) const
318 {
319 return basic_executor_type(pool_,
320 allocator_, bits_ | relationship_continuation);
321 }
322
323 /// Obtain an executor with the @c outstanding_work.tracked property.
324 /**
325 * Do not call this function directly. It is intended for use with the
326 * boost::asio::require customisation point.
327 *
328 * For example:
329 * @code auto ex1 = my_thread_pool.executor();
330 * auto ex2 = boost::asio::require(ex1,
331 * boost::asio::execution::outstanding_work.tracked); @endcode
332 */
333 BOOST_ASIO_CONSTEXPR basic_executor_type<Allocator,
334 BOOST_ASIO_UNSPECIFIED(Bits | outstanding_work_tracked)>
335 require(execution::outstanding_work_t::tracked_t) const
336 {
337 return basic_executor_type<Allocator, Bits | outstanding_work_tracked>(
338 pool_, allocator_, bits_);
339 }
340
341 /// Obtain an executor with the @c outstanding_work.untracked property.
342 /**
343 * Do not call this function directly. It is intended for use with the
344 * boost::asio::require customisation point.
345 *
346 * For example:
347 * @code auto ex1 = my_thread_pool.executor();
348 * auto ex2 = boost::asio::require(ex1,
349 * boost::asio::execution::outstanding_work.untracked); @endcode
350 */
351 BOOST_ASIO_CONSTEXPR basic_executor_type<Allocator,
352 BOOST_ASIO_UNSPECIFIED(Bits & ~outstanding_work_tracked)>
353 require(execution::outstanding_work_t::untracked_t) const
354 {
355 return basic_executor_type<Allocator, Bits & ~outstanding_work_tracked>(
356 pool_, allocator_, bits_);
357 }
358
359 /// Obtain an executor with the specified @c allocator property.
360 /**
361 * Do not call this function directly. It is intended for use with the
362 * boost::asio::require customisation point.
363 *
364 * For example:
365 * @code auto ex1 = my_thread_pool.executor();
366 * auto ex2 = boost::asio::require(ex1,
367 * boost::asio::execution::allocator(my_allocator)); @endcode
368 */
369 template <typename OtherAllocator>
370 BOOST_ASIO_CONSTEXPR basic_executor_type<OtherAllocator, Bits>
371 require(execution::allocator_t<OtherAllocator> a) const
372 {
373 return basic_executor_type<OtherAllocator, Bits>(
374 pool_, a.value(), bits_);
375 }
376
377 /// Obtain an executor with the default @c allocator property.
378 /**
379 * Do not call this function directly. It is intended for use with the
380 * boost::asio::require customisation point.
381 *
382 * For example:
383 * @code auto ex1 = my_thread_pool.executor();
384 * auto ex2 = boost::asio::require(ex1,
385 * boost::asio::execution::allocator); @endcode
386 */
387 BOOST_ASIO_CONSTEXPR basic_executor_type<std::allocator<void>, Bits>
388 require(execution::allocator_t<void>) const
389 {
390 return basic_executor_type<std::allocator<void>, Bits>(
391 pool_, std::allocator<void>(), bits_);
392 }
393
394 /// Query the current value of the @c bulk_guarantee property.
395 /**
396 * Do not call this function directly. It is intended for use with the
397 * boost::asio::query customisation point.
398 *
399 * For example:
400 * @code auto ex = my_thread_pool.executor();
401 * if (boost::asio::query(ex, boost::asio::execution::bulk_guarantee)
402 * == boost::asio::execution::bulk_guarantee.parallel)
403 * ... @endcode
404 */
405 static BOOST_ASIO_CONSTEXPR execution::bulk_guarantee_t query(
406 execution::bulk_guarantee_t) BOOST_ASIO_NOEXCEPT
407 {
408 return execution::bulk_guarantee.parallel;
409 }
410
411 /// Query the current value of the @c mapping property.
412 /**
413 * Do not call this function directly. It is intended for use with the
414 * boost::asio::query customisation point.
415 *
416 * For example:
417 * @code auto ex = my_thread_pool.executor();
418 * if (boost::asio::query(ex, boost::asio::execution::mapping)
419 * == boost::asio::execution::mapping.thread)
420 * ... @endcode
421 */
422 static BOOST_ASIO_CONSTEXPR execution::mapping_t query(
423 execution::mapping_t) BOOST_ASIO_NOEXCEPT
424 {
425 return execution::mapping.thread;
426 }
427
428 /// Query the current value of the @c context property.
429 /**
430 * Do not call this function directly. It is intended for use with the
431 * boost::asio::query customisation point.
432 *
433 * For example:
434 * @code auto ex = my_thread_pool.executor();
435 * boost::asio::thread_pool& pool = boost::asio::query(
436 * ex, boost::asio::execution::context); @endcode
437 */
438 thread_pool& query(execution::context_t) const BOOST_ASIO_NOEXCEPT
439 {
440 return *pool_;
441 }
442
443 /// Query the current value of the @c blocking property.
444 /**
445 * Do not call this function directly. It is intended for use with the
446 * boost::asio::query customisation point.
447 *
448 * For example:
449 * @code auto ex = my_thread_pool.executor();
450 * if (boost::asio::query(ex, boost::asio::execution::blocking)
451 * == boost::asio::execution::blocking.always)
452 * ... @endcode
453 */
454 BOOST_ASIO_CONSTEXPR execution::blocking_t query(
455 execution::blocking_t) const BOOST_ASIO_NOEXCEPT
456 {
457 return (bits_ & blocking_never)
458 ? execution::blocking_t(execution::blocking.never)
459 : ((Bits & blocking_always)
460 ? execution::blocking_t(execution::blocking.always)
461 : execution::blocking_t(execution::blocking.possibly));
462 }
463
464 /// Query the current value of the @c relationship property.
465 /**
466 * Do not call this function directly. It is intended for use with the
467 * boost::asio::query customisation point.
468 *
469 * For example:
470 * @code auto ex = my_thread_pool.executor();
471 * if (boost::asio::query(ex, boost::asio::execution::relationship)
472 * == boost::asio::execution::relationship.continuation)
473 * ... @endcode
474 */
475 BOOST_ASIO_CONSTEXPR execution::relationship_t query(
476 execution::relationship_t) const BOOST_ASIO_NOEXCEPT
477 {
478 return (bits_ & relationship_continuation)
479 ? execution::relationship_t(execution::relationship.continuation)
480 : execution::relationship_t(execution::relationship.fork);
481 }
482
483 /// Query the current value of the @c outstanding_work property.
484 /**
485 * Do not call this function directly. It is intended for use with the
486 * boost::asio::query customisation point.
487 *
488 * For example:
489 * @code auto ex = my_thread_pool.executor();
490 * if (boost::asio::query(ex, boost::asio::execution::outstanding_work)
491 * == boost::asio::execution::outstanding_work.tracked)
492 * ... @endcode
493 */
494 static BOOST_ASIO_CONSTEXPR execution::outstanding_work_t query(
495 execution::outstanding_work_t) BOOST_ASIO_NOEXCEPT
496 {
497 return (Bits & outstanding_work_tracked)
498 ? execution::outstanding_work_t(execution::outstanding_work.tracked)
499 : execution::outstanding_work_t(execution::outstanding_work.untracked);
500 }
501
502 /// Query the current value of the @c allocator property.
503 /**
504 * Do not call this function directly. It is intended for use with the
505 * boost::asio::query customisation point.
506 *
507 * For example:
508 * @code auto ex = my_thread_pool.executor();
509 * auto alloc = boost::asio::query(ex,
510 * boost::asio::execution::allocator); @endcode
511 */
512 template <typename OtherAllocator>
513 BOOST_ASIO_CONSTEXPR Allocator query(
514 execution::allocator_t<OtherAllocator>) const BOOST_ASIO_NOEXCEPT
515 {
516 return allocator_;
517 }
518
519 /// Query the current value of the @c allocator property.
520 /**
521 * Do not call this function directly. It is intended for use with the
522 * boost::asio::query customisation point.
523 *
524 * For example:
525 * @code auto ex = my_thread_pool.executor();
526 * auto alloc = boost::asio::query(ex,
527 * boost::asio::execution::allocator); @endcode
528 */
529 BOOST_ASIO_CONSTEXPR Allocator query(
530 execution::allocator_t<void>) const BOOST_ASIO_NOEXCEPT
531 {
532 return allocator_;
533 }
534
535 /// Query the occupancy (recommended number of work items) for the pool.
536 /**
537 * Do not call this function directly. It is intended for use with the
538 * boost::asio::query customisation point.
539 *
540 * For example:
541 * @code auto ex = my_thread_pool.executor();
542 * std::size_t occupancy = boost::asio::query(
543 * ex, boost::asio::execution::occupancy); @endcode
544 */
545 std::size_t query(execution::occupancy_t) const BOOST_ASIO_NOEXCEPT
546 {
547 return static_cast<std::size_t>(pool_->num_threads_);
548 }
549
550 /// Determine whether the thread pool is running in the current thread.
551 /**
552 * @return @c true if the current thread is running the thread pool. Otherwise
553 * returns @c false.
554 */
555 bool running_in_this_thread() const BOOST_ASIO_NOEXCEPT;
556
557 /// Compare two executors for equality.
558 /**
559 * Two executors are equal if they refer to the same underlying thread pool.
560 */
561 friend bool operator==(const basic_executor_type& a,
562 const basic_executor_type& b) BOOST_ASIO_NOEXCEPT
563 {
564 return a.pool_ == b.pool_
565 && a.allocator_ == b.allocator_
566 && a.bits_ == b.bits_;
567 }
568
569 /// Compare two executors for inequality.
570 /**
571 * Two executors are equal if they refer to the same underlying thread pool.
572 */
573 friend bool operator!=(const basic_executor_type& a,
574 const basic_executor_type& b) BOOST_ASIO_NOEXCEPT
575 {
576 return a.pool_ != b.pool_
577 || a.allocator_ != b.allocator_
578 || a.bits_ != b.bits_;
579 }
580
581 /// Execution function.
582 /**
583 * Do not call this function directly. It is intended for use with the
584 * execution::execute customisation point.
585 *
586 * For example:
587 * @code auto ex = my_thread_pool.executor();
588 * execution::execute(ex, my_function_object); @endcode
589 */
590 template <typename Function>
591 void execute(BOOST_ASIO_MOVE_ARG(Function) f) const
592 {
593 this->do_execute(BOOST_ASIO_MOVE_CAST(Function)(f),
594 integral_constant<bool, (Bits & blocking_always) != 0>());
595 }
596
597 /// Bulk execution function.
598 template <typename Function>
599 void bulk_execute(BOOST_ASIO_MOVE_ARG(Function) f, std::size_t n) const
600 {
601 this->do_bulk_execute(BOOST_ASIO_MOVE_CAST(Function)(f), n,
602 integral_constant<bool, (Bits & blocking_always) != 0>());
603 }
604
605 /// Schedule function.
606 /**
607 * Do not call this function directly. It is intended for use with the
608 * execution::schedule customisation point.
609 *
610 * @return An object that satisfies the sender concept.
611 */
612 sender_type schedule() const BOOST_ASIO_NOEXCEPT
613 {
614 return *this;
615 }
616
617 /// Connect function.
618 /**
619 * Do not call this function directly. It is intended for use with the
620 * execution::connect customisation point.
621 *
622 * @return An object of an unspecified type that satisfies the @c
623 * operation_state concept.
624 */
625 template <BOOST_ASIO_EXECUTION_RECEIVER_OF_0 Receiver>
626#if defined(GENERATING_DOCUMENTATION)
627 unspecified
628#else // defined(GENERATING_DOCUMENTATION)
629 execution::detail::as_operation<basic_executor_type, Receiver>
630#endif // defined(GENERATING_DOCUMENTATION)
631 connect(BOOST_ASIO_MOVE_ARG(Receiver) r) const
632 {
633 return execution::detail::as_operation<basic_executor_type, Receiver>(
634 *this, BOOST_ASIO_MOVE_CAST(Receiver)(r));
635 }
636
637#if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
b32b8144
FG
638 /// Obtain the underlying execution context.
639 thread_pool& context() const BOOST_ASIO_NOEXCEPT;
640
641 /// Inform the thread pool that it has some outstanding work to do.
642 /**
643 * This function is used to inform the thread pool that some work has begun.
644 * This ensures that the thread pool's join() function will not return while
645 * the work is underway.
646 */
647 void on_work_started() const BOOST_ASIO_NOEXCEPT;
648
649 /// Inform the thread pool that some work is no longer outstanding.
650 /**
651 * This function is used to inform the thread pool that some work has
652 * finished. Once the count of unfinished work reaches zero, the thread
653 * pool's join() function is permitted to exit.
654 */
655 void on_work_finished() const BOOST_ASIO_NOEXCEPT;
656
657 /// Request the thread pool to invoke the given function object.
658 /**
659 * This function is used to ask the thread pool to execute the given function
660 * object. If the current thread belongs to the pool, @c dispatch() executes
661 * the function before returning. Otherwise, the function will be scheduled
662 * to run on the thread pool.
663 *
664 * @param f The function object to be called. The executor will make
665 * a copy of the handler object as required. The function signature of the
666 * function object must be: @code void function(); @endcode
667 *
668 * @param a An allocator that may be used by the executor to allocate the
669 * internal storage needed for function invocation.
670 */
20effc67
TL
671 template <typename Function, typename OtherAllocator>
672 void dispatch(BOOST_ASIO_MOVE_ARG(Function) f,
673 const OtherAllocator& a) const;
b32b8144
FG
674
675 /// Request the thread pool to invoke the given function object.
676 /**
677 * This function is used to ask the thread pool to execute the given function
678 * object. The function object will never be executed inside @c post().
679 * Instead, it will be scheduled to run on the thread pool.
680 *
681 * @param f The function object to be called. The executor will make
682 * a copy of the handler object as required. The function signature of the
683 * function object must be: @code void function(); @endcode
684 *
685 * @param a An allocator that may be used by the executor to allocate the
686 * internal storage needed for function invocation.
687 */
20effc67
TL
688 template <typename Function, typename OtherAllocator>
689 void post(BOOST_ASIO_MOVE_ARG(Function) f,
690 const OtherAllocator& a) const;
b32b8144
FG
691
692 /// Request the thread pool to invoke the given function object.
693 /**
694 * This function is used to ask the thread pool to execute the given function
695 * object. The function object will never be executed inside @c defer().
696 * Instead, it will be scheduled to run on the thread pool.
697 *
698 * If the current thread belongs to the thread pool, @c defer() will delay
699 * scheduling the function object until the current thread returns control to
700 * the pool.
701 *
702 * @param f The function object to be called. The executor will make
703 * a copy of the handler object as required. The function signature of the
704 * function object must be: @code void function(); @endcode
705 *
706 * @param a An allocator that may be used by the executor to allocate the
707 * internal storage needed for function invocation.
708 */
20effc67
TL
709 template <typename Function, typename OtherAllocator>
710 void defer(BOOST_ASIO_MOVE_ARG(Function) f,
711 const OtherAllocator& a) const;
712#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
b32b8144 713
20effc67
TL
714private:
715 friend class thread_pool;
716 template <typename, unsigned int> friend class basic_executor_type;
b32b8144 717
20effc67
TL
718 // Constructor used by thread_pool::get_executor().
719 explicit basic_executor_type(thread_pool& p) BOOST_ASIO_NOEXCEPT
720 : pool_(&p),
721 allocator_(),
722 bits_(0)
b32b8144 723 {
20effc67
TL
724 if (Bits & outstanding_work_tracked)
725 pool_->scheduler_.work_started();
b32b8144
FG
726 }
727
20effc67
TL
728 // Constructor used by require().
729 basic_executor_type(thread_pool* p,
730 const Allocator& a, unsigned int bits) BOOST_ASIO_NOEXCEPT
731 : pool_(p),
732 allocator_(a),
733 bits_(bits)
b32b8144 734 {
20effc67
TL
735 if (Bits & outstanding_work_tracked)
736 if (pool_)
737 pool_->scheduler_.work_started();
b32b8144
FG
738 }
739
20effc67
TL
740 /// Execution helper implementation for possibly and never blocking.
741 template <typename Function>
742 void do_execute(BOOST_ASIO_MOVE_ARG(Function) f, false_type) const;
743
744 /// Execution helper implementation for always blocking.
745 template <typename Function>
746 void do_execute(BOOST_ASIO_MOVE_ARG(Function) f, true_type) const;
b32b8144 747
20effc67
TL
748 /// Bulk execution helper implementation for possibly and never blocking.
749 template <typename Function>
750 void do_bulk_execute(BOOST_ASIO_MOVE_ARG(Function) f,
751 std::size_t n, false_type) const;
752
753 /// Bulk execution helper implementation for always blocking.
754 template <typename Function>
755 void do_bulk_execute(BOOST_ASIO_MOVE_ARG(Function) f,
756 std::size_t n, true_type) const;
b32b8144
FG
757
758 // The underlying thread pool.
20effc67
TL
759 thread_pool* pool_;
760
761 // The allocator used for execution functions.
762 Allocator allocator_;
763
764 // The runtime-switched properties of the thread pool executor.
765 unsigned int bits_;
b32b8144
FG
766};
767
20effc67
TL
768#if !defined(GENERATING_DOCUMENTATION)
769
770namespace traits {
771
772#if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
773
774template <typename Allocator, unsigned int Bits>
775struct equality_comparable<
776 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>
777 >
778{
779 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
780 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
781};
782
783#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
784
785#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
786
787template <typename Allocator, unsigned int Bits, typename Function>
788struct execute_member<
789 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
790 Function
791 >
792{
793 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
794 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
795 typedef void result_type;
796};
797
798#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
799
800#if !defined(BOOST_ASIO_HAS_DEDUCED_SCHEDULE_MEMBER_TRAIT)
801
802template <typename Allocator, unsigned int Bits>
803struct schedule_member<
804 const boost::asio::thread_pool::basic_executor_type<Allocator, Bits>
805 >
806{
807 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
808 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
809 typedef boost::asio::thread_pool::basic_executor_type<
810 Allocator, Bits> result_type;
811};
812
813#endif // !defined(BOOST_ASIO_HAS_DEDUCED_SCHEDULE_MEMBER_TRAIT)
814
815#if !defined(BOOST_ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT)
816
817template <typename Allocator, unsigned int Bits, typename Receiver>
818struct connect_member<
819 const boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
820 Receiver
821 >
822{
823 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
824 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
825 typedef boost::asio::execution::detail::as_operation<
826 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
827 Receiver> result_type;
828};
829
830#endif // !defined(BOOST_ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT)
831
832#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
833
834template <typename Allocator, unsigned int Bits>
835struct require_member<
836 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
837 boost::asio::execution::blocking_t::possibly_t
838 > : boost::asio::detail::thread_pool_bits
839{
840 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
841 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
842 typedef boost::asio::thread_pool::basic_executor_type<
843 Allocator, Bits & ~blocking_mask> result_type;
844};
845
846template <typename Allocator, unsigned int Bits>
847struct require_member<
848 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
849 boost::asio::execution::blocking_t::always_t
850 > : boost::asio::detail::thread_pool_bits
851{
852 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
853 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
854 typedef boost::asio::thread_pool::basic_executor_type<Allocator,
855 (Bits & ~blocking_mask) | blocking_always> result_type;
856};
857
858template <typename Allocator, unsigned int Bits>
859struct require_member<
860 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
861 boost::asio::execution::blocking_t::never_t
862 > : boost::asio::detail::thread_pool_bits
863{
864 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
865 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
866 typedef boost::asio::thread_pool::basic_executor_type<
867 Allocator, Bits & ~blocking_mask> result_type;
868};
869
870template <typename Allocator, unsigned int Bits>
871struct require_member<
872 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
873 boost::asio::execution::relationship_t::fork_t
874 >
875{
876 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
877 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
878 typedef boost::asio::thread_pool::basic_executor_type<
879 Allocator, Bits> result_type;
880};
881
882template <typename Allocator, unsigned int Bits>
883struct require_member<
884 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
885 boost::asio::execution::relationship_t::continuation_t
886 >
887{
888 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
889 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
890 typedef boost::asio::thread_pool::basic_executor_type<
891 Allocator, Bits> result_type;
892};
893
894template <typename Allocator, unsigned int Bits>
895struct require_member<
896 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
897 boost::asio::execution::outstanding_work_t::tracked_t
898 > : boost::asio::detail::thread_pool_bits
899{
900 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
901 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
902 typedef boost::asio::thread_pool::basic_executor_type<
903 Allocator, Bits | outstanding_work_tracked> result_type;
904};
905
906template <typename Allocator, unsigned int Bits>
907struct require_member<
908 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
909 boost::asio::execution::outstanding_work_t::untracked_t
910 > : boost::asio::detail::thread_pool_bits
911{
912 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
913 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
914 typedef boost::asio::thread_pool::basic_executor_type<
915 Allocator, Bits & ~outstanding_work_tracked> result_type;
916};
917
918template <typename Allocator, unsigned int Bits>
919struct require_member<
920 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
921 boost::asio::execution::allocator_t<void>
922 >
923{
924 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
925 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
926 typedef boost::asio::thread_pool::basic_executor_type<
927 std::allocator<void>, Bits> result_type;
928};
929
930template <unsigned int Bits,
931 typename Allocator, typename OtherAllocator>
932struct require_member<
933 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
934 boost::asio::execution::allocator_t<OtherAllocator>
935 >
936{
937 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
938 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
939 typedef boost::asio::thread_pool::basic_executor_type<
940 OtherAllocator, Bits> result_type;
941};
942
943#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
944
945#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
946
947template <typename Allocator, unsigned int Bits, typename Property>
948struct query_static_constexpr_member<
949 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
950 Property,
951 typename boost::asio::enable_if<
952 boost::asio::is_convertible<
953 Property,
954 boost::asio::execution::bulk_guarantee_t
955 >::value
956 >::type
957 >
958{
959 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
960 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
961 typedef boost::asio::execution::bulk_guarantee_t::parallel_t result_type;
962
963 static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT
964 {
965 return result_type();
966 }
967};
968
969template <typename Allocator, unsigned int Bits, typename Property>
970struct query_static_constexpr_member<
971 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
972 Property,
973 typename boost::asio::enable_if<
974 boost::asio::is_convertible<
975 Property,
976 boost::asio::execution::outstanding_work_t
977 >::value
978 >::type
979 > : boost::asio::detail::thread_pool_bits
980{
981 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
982 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
983 typedef boost::asio::execution::outstanding_work_t result_type;
984
985 static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT
986 {
987 return (Bits & outstanding_work_tracked)
988 ? execution::outstanding_work_t(execution::outstanding_work.tracked)
989 : execution::outstanding_work_t(execution::outstanding_work.untracked);
990 }
991};
992
993template <typename Allocator, unsigned int Bits, typename Property>
994struct query_static_constexpr_member<
995 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
996 Property,
997 typename boost::asio::enable_if<
998 boost::asio::is_convertible<
999 Property,
1000 boost::asio::execution::mapping_t
1001 >::value
1002 >::type
1003 >
1004{
1005 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1006 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1007 typedef boost::asio::execution::mapping_t::thread_t result_type;
1008
1009 static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT
1010 {
1011 return result_type();
1012 }
1013};
1014
1015#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
1016
1017#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
1018
1019template <typename Allocator, unsigned int Bits, typename Property>
1020struct query_member<
1021 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
1022 Property,
1023 typename boost::asio::enable_if<
1024 boost::asio::is_convertible<
1025 Property,
1026 boost::asio::execution::blocking_t
1027 >::value
1028 >::type
1029 >
1030{
1031 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1032 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1033 typedef boost::asio::execution::blocking_t result_type;
1034};
1035
1036template <typename Allocator, unsigned int Bits, typename Property>
1037struct query_member<
1038 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
1039 Property,
1040 typename boost::asio::enable_if<
1041 boost::asio::is_convertible<
1042 Property,
1043 boost::asio::execution::relationship_t
1044 >::value
1045 >::type
1046 >
1047{
1048 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1049 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1050 typedef boost::asio::execution::relationship_t result_type;
1051};
1052
1053template <typename Allocator, unsigned int Bits>
1054struct query_member<
1055 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
1056 boost::asio::execution::occupancy_t
1057 >
1058{
1059 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1060 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1061 typedef std::size_t result_type;
1062};
1063
1064template <typename Allocator, unsigned int Bits>
1065struct query_member<
1066 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
1067 boost::asio::execution::context_t
1068 >
1069{
1070 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1071 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1072 typedef boost::asio::thread_pool& result_type;
1073};
1074
1075template <typename Allocator, unsigned int Bits>
1076struct query_member<
1077 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
1078 boost::asio::execution::allocator_t<void>
1079 >
1080{
1081 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1082 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1083 typedef Allocator result_type;
1084};
1085
1086template <typename Allocator, unsigned int Bits, typename OtherAllocator>
1087struct query_member<
1088 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
1089 boost::asio::execution::allocator_t<OtherAllocator>
1090 >
1091{
1092 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1093 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1094 typedef Allocator result_type;
1095};
1096
1097#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
1098
1099} // namespace traits
1100
1101#endif // !defined(GENERATING_DOCUMENTATION)
1102
b32b8144
FG
1103} // namespace asio
1104} // namespace boost
1105
1106#include <boost/asio/detail/pop_options.hpp>
1107
1108#include <boost/asio/impl/thread_pool.hpp>
1109#if defined(BOOST_ASIO_HEADER_ONLY)
1110# include <boost/asio/impl/thread_pool.ipp>
1111#endif // defined(BOOST_ASIO_HEADER_ONLY)
1112
1113#endif // BOOST_ASIO_THREAD_POOL_HPP