]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/asio/thread_pool.hpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / boost / asio / thread_pool.hpp
CommitLineData
b32b8144
FG
1//
2// thread_pool.hpp
3// ~~~~~~~~~~~~~~~
4//
1e59de90 5// Copyright (c) 2003-2022 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
1e59de90
TL
234#if !defined(GENERATING_DOCUMENTATION)
235private:
236 friend struct boost_asio_require_fn::impl;
237 friend struct boost_asio_prefer_fn::impl;
238#endif // !defined(GENERATING_DOCUMENTATION)
239
20effc67
TL
240 /// Obtain an executor with the @c blocking.possibly property.
241 /**
242 * Do not call this function directly. It is intended for use with the
243 * boost::asio::require customisation point.
244 *
245 * For example:
246 * @code auto ex1 = my_thread_pool.executor();
247 * auto ex2 = boost::asio::require(ex1,
248 * boost::asio::execution::blocking.possibly); @endcode
249 */
250 BOOST_ASIO_CONSTEXPR basic_executor_type<Allocator,
251 BOOST_ASIO_UNSPECIFIED(Bits & ~blocking_mask)>
252 require(execution::blocking_t::possibly_t) const
253 {
254 return basic_executor_type<Allocator, Bits & ~blocking_mask>(
255 pool_, allocator_, bits_ & ~blocking_mask);
256 }
257
258 /// Obtain an executor with the @c blocking.always property.
259 /**
260 * Do not call this function directly. It is intended for use with the
261 * boost::asio::require customisation point.
262 *
263 * For example:
264 * @code auto ex1 = my_thread_pool.executor();
265 * auto ex2 = boost::asio::require(ex1,
266 * boost::asio::execution::blocking.always); @endcode
267 */
268 BOOST_ASIO_CONSTEXPR basic_executor_type<Allocator,
269 BOOST_ASIO_UNSPECIFIED((Bits & ~blocking_mask) | blocking_always)>
270 require(execution::blocking_t::always_t) const
271 {
272 return basic_executor_type<Allocator,
273 BOOST_ASIO_UNSPECIFIED((Bits & ~blocking_mask) | blocking_always)>(
274 pool_, allocator_, bits_ & ~blocking_mask);
275 }
276
277 /// Obtain an executor with the @c blocking.never property.
278 /**
279 * Do not call this function directly. It is intended for use with the
280 * boost::asio::require customisation point.
281 *
282 * For example:
283 * @code auto ex1 = my_thread_pool.executor();
284 * auto ex2 = boost::asio::require(ex1,
285 * boost::asio::execution::blocking.never); @endcode
286 */
287 BOOST_ASIO_CONSTEXPR basic_executor_type<Allocator,
288 BOOST_ASIO_UNSPECIFIED(Bits & ~blocking_mask)>
289 require(execution::blocking_t::never_t) const
290 {
291 return basic_executor_type<Allocator, Bits & ~blocking_mask>(
292 pool_, allocator_, (bits_ & ~blocking_mask) | blocking_never);
293 }
294
295 /// Obtain an executor with the @c relationship.fork property.
296 /**
297 * Do not call this function directly. It is intended for use with the
298 * boost::asio::require customisation point.
299 *
300 * For example:
301 * @code auto ex1 = my_thread_pool.executor();
302 * auto ex2 = boost::asio::require(ex1,
303 * boost::asio::execution::relationship.fork); @endcode
304 */
305 BOOST_ASIO_CONSTEXPR basic_executor_type require(
306 execution::relationship_t::fork_t) const
307 {
308 return basic_executor_type(pool_,
309 allocator_, bits_ & ~relationship_continuation);
310 }
311
312 /// Obtain an executor with the @c relationship.continuation property.
313 /**
314 * Do not call this function directly. It is intended for use with the
315 * boost::asio::require customisation point.
316 *
317 * For example:
318 * @code auto ex1 = my_thread_pool.executor();
319 * auto ex2 = boost::asio::require(ex1,
320 * boost::asio::execution::relationship.continuation); @endcode
321 */
322 BOOST_ASIO_CONSTEXPR basic_executor_type require(
323 execution::relationship_t::continuation_t) const
324 {
325 return basic_executor_type(pool_,
326 allocator_, bits_ | relationship_continuation);
327 }
328
329 /// Obtain an executor with the @c outstanding_work.tracked property.
330 /**
331 * Do not call this function directly. It is intended for use with the
332 * boost::asio::require customisation point.
333 *
334 * For example:
335 * @code auto ex1 = my_thread_pool.executor();
336 * auto ex2 = boost::asio::require(ex1,
337 * boost::asio::execution::outstanding_work.tracked); @endcode
338 */
339 BOOST_ASIO_CONSTEXPR basic_executor_type<Allocator,
340 BOOST_ASIO_UNSPECIFIED(Bits | outstanding_work_tracked)>
341 require(execution::outstanding_work_t::tracked_t) const
342 {
343 return basic_executor_type<Allocator, Bits | outstanding_work_tracked>(
344 pool_, allocator_, bits_);
345 }
346
347 /// Obtain an executor with the @c outstanding_work.untracked property.
348 /**
349 * Do not call this function directly. It is intended for use with the
350 * boost::asio::require customisation point.
351 *
352 * For example:
353 * @code auto ex1 = my_thread_pool.executor();
354 * auto ex2 = boost::asio::require(ex1,
355 * boost::asio::execution::outstanding_work.untracked); @endcode
356 */
357 BOOST_ASIO_CONSTEXPR basic_executor_type<Allocator,
358 BOOST_ASIO_UNSPECIFIED(Bits & ~outstanding_work_tracked)>
359 require(execution::outstanding_work_t::untracked_t) const
360 {
361 return basic_executor_type<Allocator, Bits & ~outstanding_work_tracked>(
362 pool_, allocator_, bits_);
363 }
364
365 /// Obtain an executor with the specified @c allocator property.
366 /**
367 * Do not call this function directly. It is intended for use with the
368 * boost::asio::require customisation point.
369 *
370 * For example:
371 * @code auto ex1 = my_thread_pool.executor();
372 * auto ex2 = boost::asio::require(ex1,
373 * boost::asio::execution::allocator(my_allocator)); @endcode
374 */
375 template <typename OtherAllocator>
376 BOOST_ASIO_CONSTEXPR basic_executor_type<OtherAllocator, Bits>
377 require(execution::allocator_t<OtherAllocator> a) const
378 {
379 return basic_executor_type<OtherAllocator, Bits>(
380 pool_, a.value(), bits_);
381 }
382
383 /// Obtain an executor with the default @c allocator property.
384 /**
385 * Do not call this function directly. It is intended for use with the
386 * boost::asio::require customisation point.
387 *
388 * For example:
389 * @code auto ex1 = my_thread_pool.executor();
390 * auto ex2 = boost::asio::require(ex1,
391 * boost::asio::execution::allocator); @endcode
392 */
393 BOOST_ASIO_CONSTEXPR basic_executor_type<std::allocator<void>, Bits>
394 require(execution::allocator_t<void>) const
395 {
396 return basic_executor_type<std::allocator<void>, Bits>(
397 pool_, std::allocator<void>(), bits_);
398 }
399
1e59de90
TL
400#if !defined(GENERATING_DOCUMENTATION)
401private:
402 friend struct boost_asio_query_fn::impl;
403 friend struct boost::asio::execution::detail::mapping_t<0>;
404 friend struct boost::asio::execution::detail::outstanding_work_t<0>;
405#endif // !defined(GENERATING_DOCUMENTATION)
406
20effc67
TL
407 /// Query the current value of the @c bulk_guarantee property.
408 /**
409 * Do not call this function directly. It is intended for use with the
410 * boost::asio::query customisation point.
411 *
412 * For example:
413 * @code auto ex = my_thread_pool.executor();
414 * if (boost::asio::query(ex, boost::asio::execution::bulk_guarantee)
415 * == boost::asio::execution::bulk_guarantee.parallel)
416 * ... @endcode
417 */
418 static BOOST_ASIO_CONSTEXPR execution::bulk_guarantee_t query(
419 execution::bulk_guarantee_t) BOOST_ASIO_NOEXCEPT
420 {
421 return execution::bulk_guarantee.parallel;
422 }
423
424 /// Query the current value of the @c mapping property.
425 /**
426 * Do not call this function directly. It is intended for use with the
427 * boost::asio::query customisation point.
428 *
429 * For example:
430 * @code auto ex = my_thread_pool.executor();
431 * if (boost::asio::query(ex, boost::asio::execution::mapping)
432 * == boost::asio::execution::mapping.thread)
433 * ... @endcode
434 */
435 static BOOST_ASIO_CONSTEXPR execution::mapping_t query(
436 execution::mapping_t) BOOST_ASIO_NOEXCEPT
437 {
438 return execution::mapping.thread;
439 }
440
441 /// Query the current value of the @c context property.
442 /**
443 * Do not call this function directly. It is intended for use with the
444 * boost::asio::query customisation point.
445 *
446 * For example:
447 * @code auto ex = my_thread_pool.executor();
448 * boost::asio::thread_pool& pool = boost::asio::query(
449 * ex, boost::asio::execution::context); @endcode
450 */
451 thread_pool& query(execution::context_t) const BOOST_ASIO_NOEXCEPT
452 {
453 return *pool_;
454 }
455
456 /// Query the current value of the @c blocking property.
457 /**
458 * Do not call this function directly. It is intended for use with the
459 * boost::asio::query customisation point.
460 *
461 * For example:
462 * @code auto ex = my_thread_pool.executor();
463 * if (boost::asio::query(ex, boost::asio::execution::blocking)
464 * == boost::asio::execution::blocking.always)
465 * ... @endcode
466 */
467 BOOST_ASIO_CONSTEXPR execution::blocking_t query(
468 execution::blocking_t) const BOOST_ASIO_NOEXCEPT
469 {
470 return (bits_ & blocking_never)
471 ? execution::blocking_t(execution::blocking.never)
472 : ((Bits & blocking_always)
473 ? execution::blocking_t(execution::blocking.always)
474 : execution::blocking_t(execution::blocking.possibly));
475 }
476
477 /// Query the current value of the @c relationship property.
478 /**
479 * Do not call this function directly. It is intended for use with the
480 * boost::asio::query customisation point.
481 *
482 * For example:
483 * @code auto ex = my_thread_pool.executor();
484 * if (boost::asio::query(ex, boost::asio::execution::relationship)
485 * == boost::asio::execution::relationship.continuation)
486 * ... @endcode
487 */
488 BOOST_ASIO_CONSTEXPR execution::relationship_t query(
489 execution::relationship_t) const BOOST_ASIO_NOEXCEPT
490 {
491 return (bits_ & relationship_continuation)
492 ? execution::relationship_t(execution::relationship.continuation)
493 : execution::relationship_t(execution::relationship.fork);
494 }
495
496 /// Query the current value of the @c outstanding_work property.
497 /**
498 * Do not call this function directly. It is intended for use with the
499 * boost::asio::query customisation point.
500 *
501 * For example:
502 * @code auto ex = my_thread_pool.executor();
503 * if (boost::asio::query(ex, boost::asio::execution::outstanding_work)
504 * == boost::asio::execution::outstanding_work.tracked)
505 * ... @endcode
506 */
507 static BOOST_ASIO_CONSTEXPR execution::outstanding_work_t query(
508 execution::outstanding_work_t) BOOST_ASIO_NOEXCEPT
509 {
510 return (Bits & outstanding_work_tracked)
511 ? execution::outstanding_work_t(execution::outstanding_work.tracked)
512 : execution::outstanding_work_t(execution::outstanding_work.untracked);
513 }
514
515 /// Query the current value of the @c allocator property.
516 /**
517 * Do not call this function directly. It is intended for use with the
518 * boost::asio::query customisation point.
519 *
520 * For example:
521 * @code auto ex = my_thread_pool.executor();
522 * auto alloc = boost::asio::query(ex,
523 * boost::asio::execution::allocator); @endcode
524 */
525 template <typename OtherAllocator>
526 BOOST_ASIO_CONSTEXPR Allocator query(
527 execution::allocator_t<OtherAllocator>) const BOOST_ASIO_NOEXCEPT
528 {
529 return allocator_;
530 }
531
532 /// Query the current value of the @c allocator property.
533 /**
534 * Do not call this function directly. It is intended for use with the
535 * boost::asio::query customisation point.
536 *
537 * For example:
538 * @code auto ex = my_thread_pool.executor();
539 * auto alloc = boost::asio::query(ex,
540 * boost::asio::execution::allocator); @endcode
541 */
542 BOOST_ASIO_CONSTEXPR Allocator query(
543 execution::allocator_t<void>) const BOOST_ASIO_NOEXCEPT
544 {
545 return allocator_;
546 }
547
548 /// Query the occupancy (recommended number of work items) for the pool.
549 /**
550 * Do not call this function directly. It is intended for use with the
551 * boost::asio::query customisation point.
552 *
553 * For example:
554 * @code auto ex = my_thread_pool.executor();
555 * std::size_t occupancy = boost::asio::query(
556 * ex, boost::asio::execution::occupancy); @endcode
557 */
558 std::size_t query(execution::occupancy_t) const BOOST_ASIO_NOEXCEPT
559 {
560 return static_cast<std::size_t>(pool_->num_threads_);
561 }
562
1e59de90 563public:
20effc67
TL
564 /// Determine whether the thread pool is running in the current thread.
565 /**
566 * @return @c true if the current thread is running the thread pool. Otherwise
567 * returns @c false.
568 */
569 bool running_in_this_thread() const BOOST_ASIO_NOEXCEPT;
570
571 /// Compare two executors for equality.
572 /**
573 * Two executors are equal if they refer to the same underlying thread pool.
574 */
575 friend bool operator==(const basic_executor_type& a,
576 const basic_executor_type& b) BOOST_ASIO_NOEXCEPT
577 {
578 return a.pool_ == b.pool_
579 && a.allocator_ == b.allocator_
580 && a.bits_ == b.bits_;
581 }
582
583 /// Compare two executors for inequality.
584 /**
585 * Two executors are equal if they refer to the same underlying thread pool.
586 */
587 friend bool operator!=(const basic_executor_type& a,
588 const basic_executor_type& b) BOOST_ASIO_NOEXCEPT
589 {
590 return a.pool_ != b.pool_
591 || a.allocator_ != b.allocator_
592 || a.bits_ != b.bits_;
593 }
594
1e59de90
TL
595#if !defined(GENERATING_DOCUMENTATION)
596private:
597 friend struct boost_asio_execution_execute_fn::impl;
598#endif // !defined(GENERATING_DOCUMENTATION)
599
20effc67
TL
600 /// Execution function.
601 /**
602 * Do not call this function directly. It is intended for use with the
603 * execution::execute customisation point.
604 *
605 * For example:
606 * @code auto ex = my_thread_pool.executor();
607 * execution::execute(ex, my_function_object); @endcode
608 */
609 template <typename Function>
610 void execute(BOOST_ASIO_MOVE_ARG(Function) f) const
611 {
612 this->do_execute(BOOST_ASIO_MOVE_CAST(Function)(f),
613 integral_constant<bool, (Bits & blocking_always) != 0>());
614 }
615
1e59de90 616public:
20effc67
TL
617 /// Bulk execution function.
618 template <typename Function>
619 void bulk_execute(BOOST_ASIO_MOVE_ARG(Function) f, std::size_t n) const
620 {
621 this->do_bulk_execute(BOOST_ASIO_MOVE_CAST(Function)(f), n,
622 integral_constant<bool, (Bits & blocking_always) != 0>());
623 }
624
625 /// Schedule function.
626 /**
627 * Do not call this function directly. It is intended for use with the
628 * execution::schedule customisation point.
629 *
630 * @return An object that satisfies the sender concept.
631 */
632 sender_type schedule() const BOOST_ASIO_NOEXCEPT
633 {
634 return *this;
635 }
636
637 /// Connect function.
638 /**
639 * Do not call this function directly. It is intended for use with the
640 * execution::connect customisation point.
641 *
642 * @return An object of an unspecified type that satisfies the @c
643 * operation_state concept.
644 */
645 template <BOOST_ASIO_EXECUTION_RECEIVER_OF_0 Receiver>
646#if defined(GENERATING_DOCUMENTATION)
647 unspecified
648#else // defined(GENERATING_DOCUMENTATION)
649 execution::detail::as_operation<basic_executor_type, Receiver>
650#endif // defined(GENERATING_DOCUMENTATION)
651 connect(BOOST_ASIO_MOVE_ARG(Receiver) r) const
652 {
653 return execution::detail::as_operation<basic_executor_type, Receiver>(
654 *this, BOOST_ASIO_MOVE_CAST(Receiver)(r));
655 }
656
657#if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
b32b8144
FG
658 /// Obtain the underlying execution context.
659 thread_pool& context() const BOOST_ASIO_NOEXCEPT;
660
661 /// Inform the thread pool that it has some outstanding work to do.
662 /**
663 * This function is used to inform the thread pool that some work has begun.
664 * This ensures that the thread pool's join() function will not return while
665 * the work is underway.
666 */
667 void on_work_started() const BOOST_ASIO_NOEXCEPT;
668
669 /// Inform the thread pool that some work is no longer outstanding.
670 /**
671 * This function is used to inform the thread pool that some work has
672 * finished. Once the count of unfinished work reaches zero, the thread
673 * pool's join() function is permitted to exit.
674 */
675 void on_work_finished() const BOOST_ASIO_NOEXCEPT;
676
677 /// Request the thread pool to invoke the given function object.
678 /**
679 * This function is used to ask the thread pool to execute the given function
680 * object. If the current thread belongs to the pool, @c dispatch() executes
681 * the function before returning. Otherwise, the function will be scheduled
682 * to run on the thread pool.
683 *
684 * @param f The function object to be called. The executor will make
685 * a copy of the handler object as required. The function signature of the
686 * function object must be: @code void function(); @endcode
687 *
688 * @param a An allocator that may be used by the executor to allocate the
689 * internal storage needed for function invocation.
690 */
20effc67
TL
691 template <typename Function, typename OtherAllocator>
692 void dispatch(BOOST_ASIO_MOVE_ARG(Function) f,
693 const OtherAllocator& a) const;
b32b8144
FG
694
695 /// Request the thread pool to invoke the given function object.
696 /**
697 * This function is used to ask the thread pool to execute the given function
698 * object. The function object will never be executed inside @c post().
699 * Instead, it will be scheduled to run on the thread pool.
700 *
701 * @param f The function object to be called. The executor will make
702 * a copy of the handler object as required. The function signature of the
703 * function object must be: @code void function(); @endcode
704 *
705 * @param a An allocator that may be used by the executor to allocate the
706 * internal storage needed for function invocation.
707 */
20effc67
TL
708 template <typename Function, typename OtherAllocator>
709 void post(BOOST_ASIO_MOVE_ARG(Function) f,
710 const OtherAllocator& a) const;
b32b8144
FG
711
712 /// Request the thread pool to invoke the given function object.
713 /**
714 * This function is used to ask the thread pool to execute the given function
715 * object. The function object will never be executed inside @c defer().
716 * Instead, it will be scheduled to run on the thread pool.
717 *
718 * If the current thread belongs to the thread pool, @c defer() will delay
719 * scheduling the function object until the current thread returns control to
720 * the pool.
721 *
722 * @param f The function object to be called. The executor will make
723 * a copy of the handler object as required. The function signature of the
724 * function object must be: @code void function(); @endcode
725 *
726 * @param a An allocator that may be used by the executor to allocate the
727 * internal storage needed for function invocation.
728 */
20effc67
TL
729 template <typename Function, typename OtherAllocator>
730 void defer(BOOST_ASIO_MOVE_ARG(Function) f,
731 const OtherAllocator& a) const;
732#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
b32b8144 733
20effc67
TL
734private:
735 friend class thread_pool;
736 template <typename, unsigned int> friend class basic_executor_type;
b32b8144 737
20effc67
TL
738 // Constructor used by thread_pool::get_executor().
739 explicit basic_executor_type(thread_pool& p) BOOST_ASIO_NOEXCEPT
740 : pool_(&p),
741 allocator_(),
742 bits_(0)
b32b8144 743 {
20effc67
TL
744 if (Bits & outstanding_work_tracked)
745 pool_->scheduler_.work_started();
b32b8144
FG
746 }
747
20effc67
TL
748 // Constructor used by require().
749 basic_executor_type(thread_pool* p,
750 const Allocator& a, unsigned int bits) BOOST_ASIO_NOEXCEPT
751 : pool_(p),
752 allocator_(a),
753 bits_(bits)
b32b8144 754 {
20effc67
TL
755 if (Bits & outstanding_work_tracked)
756 if (pool_)
757 pool_->scheduler_.work_started();
b32b8144
FG
758 }
759
20effc67
TL
760 /// Execution helper implementation for possibly and never blocking.
761 template <typename Function>
762 void do_execute(BOOST_ASIO_MOVE_ARG(Function) f, false_type) const;
763
764 /// Execution helper implementation for always blocking.
765 template <typename Function>
766 void do_execute(BOOST_ASIO_MOVE_ARG(Function) f, true_type) const;
b32b8144 767
20effc67
TL
768 /// Bulk execution helper implementation for possibly and never blocking.
769 template <typename Function>
770 void do_bulk_execute(BOOST_ASIO_MOVE_ARG(Function) f,
771 std::size_t n, false_type) const;
772
773 /// Bulk execution helper implementation for always blocking.
774 template <typename Function>
775 void do_bulk_execute(BOOST_ASIO_MOVE_ARG(Function) f,
776 std::size_t n, true_type) const;
b32b8144
FG
777
778 // The underlying thread pool.
20effc67
TL
779 thread_pool* pool_;
780
781 // The allocator used for execution functions.
782 Allocator allocator_;
783
784 // The runtime-switched properties of the thread pool executor.
785 unsigned int bits_;
b32b8144
FG
786};
787
20effc67
TL
788#if !defined(GENERATING_DOCUMENTATION)
789
790namespace traits {
791
792#if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
793
794template <typename Allocator, unsigned int Bits>
795struct equality_comparable<
796 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>
797 >
798{
799 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
800 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
801};
802
803#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
804
805#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
806
807template <typename Allocator, unsigned int Bits, typename Function>
808struct execute_member<
809 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
810 Function
811 >
812{
813 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
814 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
815 typedef void result_type;
816};
817
818#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
819
820#if !defined(BOOST_ASIO_HAS_DEDUCED_SCHEDULE_MEMBER_TRAIT)
821
822template <typename Allocator, unsigned int Bits>
823struct schedule_member<
824 const boost::asio::thread_pool::basic_executor_type<Allocator, Bits>
825 >
826{
827 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
828 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
829 typedef boost::asio::thread_pool::basic_executor_type<
830 Allocator, Bits> result_type;
831};
832
833#endif // !defined(BOOST_ASIO_HAS_DEDUCED_SCHEDULE_MEMBER_TRAIT)
834
835#if !defined(BOOST_ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT)
836
837template <typename Allocator, unsigned int Bits, typename Receiver>
838struct connect_member<
839 const boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
840 Receiver
841 >
842{
843 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
844 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
845 typedef boost::asio::execution::detail::as_operation<
846 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
847 Receiver> result_type;
848};
849
850#endif // !defined(BOOST_ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT)
851
852#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
853
854template <typename Allocator, unsigned int Bits>
855struct require_member<
856 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
857 boost::asio::execution::blocking_t::possibly_t
858 > : boost::asio::detail::thread_pool_bits
859{
860 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
861 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
862 typedef boost::asio::thread_pool::basic_executor_type<
863 Allocator, Bits & ~blocking_mask> result_type;
864};
865
866template <typename Allocator, unsigned int Bits>
867struct require_member<
868 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
869 boost::asio::execution::blocking_t::always_t
870 > : boost::asio::detail::thread_pool_bits
871{
872 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
873 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
874 typedef boost::asio::thread_pool::basic_executor_type<Allocator,
875 (Bits & ~blocking_mask) | blocking_always> result_type;
876};
877
878template <typename Allocator, unsigned int Bits>
879struct require_member<
880 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
881 boost::asio::execution::blocking_t::never_t
882 > : boost::asio::detail::thread_pool_bits
883{
884 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
885 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
886 typedef boost::asio::thread_pool::basic_executor_type<
887 Allocator, Bits & ~blocking_mask> result_type;
888};
889
890template <typename Allocator, unsigned int Bits>
891struct require_member<
892 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
893 boost::asio::execution::relationship_t::fork_t
894 >
895{
896 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
897 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
898 typedef boost::asio::thread_pool::basic_executor_type<
899 Allocator, Bits> result_type;
900};
901
902template <typename Allocator, unsigned int Bits>
903struct require_member<
904 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
905 boost::asio::execution::relationship_t::continuation_t
906 >
907{
908 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
909 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
910 typedef boost::asio::thread_pool::basic_executor_type<
911 Allocator, Bits> result_type;
912};
913
914template <typename Allocator, unsigned int Bits>
915struct require_member<
916 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
917 boost::asio::execution::outstanding_work_t::tracked_t
918 > : boost::asio::detail::thread_pool_bits
919{
920 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
921 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
922 typedef boost::asio::thread_pool::basic_executor_type<
923 Allocator, Bits | outstanding_work_tracked> result_type;
924};
925
926template <typename Allocator, unsigned int Bits>
927struct require_member<
928 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
929 boost::asio::execution::outstanding_work_t::untracked_t
930 > : boost::asio::detail::thread_pool_bits
931{
932 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
933 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
934 typedef boost::asio::thread_pool::basic_executor_type<
935 Allocator, Bits & ~outstanding_work_tracked> result_type;
936};
937
938template <typename Allocator, unsigned int Bits>
939struct require_member<
940 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
941 boost::asio::execution::allocator_t<void>
942 >
943{
944 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
945 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
946 typedef boost::asio::thread_pool::basic_executor_type<
947 std::allocator<void>, Bits> result_type;
948};
949
950template <unsigned int Bits,
951 typename Allocator, typename OtherAllocator>
952struct require_member<
953 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
954 boost::asio::execution::allocator_t<OtherAllocator>
955 >
956{
957 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
958 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false);
959 typedef boost::asio::thread_pool::basic_executor_type<
960 OtherAllocator, Bits> result_type;
961};
962
963#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
964
965#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
966
967template <typename Allocator, unsigned int Bits, typename Property>
968struct query_static_constexpr_member<
969 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
970 Property,
971 typename boost::asio::enable_if<
972 boost::asio::is_convertible<
973 Property,
974 boost::asio::execution::bulk_guarantee_t
975 >::value
976 >::type
977 >
978{
979 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
980 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
981 typedef boost::asio::execution::bulk_guarantee_t::parallel_t result_type;
982
983 static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT
984 {
985 return result_type();
986 }
987};
988
989template <typename Allocator, unsigned int Bits, typename Property>
990struct query_static_constexpr_member<
991 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
992 Property,
993 typename boost::asio::enable_if<
994 boost::asio::is_convertible<
995 Property,
996 boost::asio::execution::outstanding_work_t
997 >::value
998 >::type
999 > : boost::asio::detail::thread_pool_bits
1000{
1001 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1002 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1003 typedef boost::asio::execution::outstanding_work_t result_type;
1004
1005 static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT
1006 {
1007 return (Bits & outstanding_work_tracked)
1008 ? execution::outstanding_work_t(execution::outstanding_work.tracked)
1009 : execution::outstanding_work_t(execution::outstanding_work.untracked);
1010 }
1011};
1012
1013template <typename Allocator, unsigned int Bits, typename Property>
1014struct query_static_constexpr_member<
1015 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
1016 Property,
1017 typename boost::asio::enable_if<
1018 boost::asio::is_convertible<
1019 Property,
1020 boost::asio::execution::mapping_t
1021 >::value
1022 >::type
1023 >
1024{
1025 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1026 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1027 typedef boost::asio::execution::mapping_t::thread_t result_type;
1028
1029 static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT
1030 {
1031 return result_type();
1032 }
1033};
1034
1035#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
1036
1037#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
1038
1039template <typename Allocator, unsigned int Bits, typename Property>
1040struct query_member<
1041 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
1042 Property,
1043 typename boost::asio::enable_if<
1044 boost::asio::is_convertible<
1045 Property,
1046 boost::asio::execution::blocking_t
1047 >::value
1048 >::type
1049 >
1050{
1051 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1052 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1053 typedef boost::asio::execution::blocking_t result_type;
1054};
1055
1056template <typename Allocator, unsigned int Bits, typename Property>
1057struct query_member<
1058 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
1059 Property,
1060 typename boost::asio::enable_if<
1061 boost::asio::is_convertible<
1062 Property,
1063 boost::asio::execution::relationship_t
1064 >::value
1065 >::type
1066 >
1067{
1068 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1069 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1070 typedef boost::asio::execution::relationship_t result_type;
1071};
1072
1073template <typename Allocator, unsigned int Bits>
1074struct query_member<
1075 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
1076 boost::asio::execution::occupancy_t
1077 >
1078{
1079 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1080 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1081 typedef std::size_t result_type;
1082};
1083
1084template <typename Allocator, unsigned int Bits>
1085struct query_member<
1086 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
1087 boost::asio::execution::context_t
1088 >
1089{
1090 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1091 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1092 typedef boost::asio::thread_pool& result_type;
1093};
1094
1095template <typename Allocator, unsigned int Bits>
1096struct query_member<
1097 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
1098 boost::asio::execution::allocator_t<void>
1099 >
1100{
1101 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1102 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1103 typedef Allocator result_type;
1104};
1105
1106template <typename Allocator, unsigned int Bits, typename OtherAllocator>
1107struct query_member<
1108 boost::asio::thread_pool::basic_executor_type<Allocator, Bits>,
1109 boost::asio::execution::allocator_t<OtherAllocator>
1110 >
1111{
1112 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
1113 BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
1114 typedef Allocator result_type;
1115};
1116
1117#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
1118
1119} // namespace traits
1120
1e59de90
TL
1121namespace execution {
1122
1123template <>
1124struct is_executor<thread_pool> : false_type
1125{
1126};
1127
1128} // namespace execution
1129
20effc67
TL
1130#endif // !defined(GENERATING_DOCUMENTATION)
1131
b32b8144
FG
1132} // namespace asio
1133} // namespace boost
1134
1135#include <boost/asio/detail/pop_options.hpp>
1136
1137#include <boost/asio/impl/thread_pool.hpp>
1138#if defined(BOOST_ASIO_HEADER_ONLY)
1139# include <boost/asio/impl/thread_pool.ipp>
1140#endif // defined(BOOST_ASIO_HEADER_ONLY)
1141
1142#endif // BOOST_ASIO_THREAD_POOL_HPP