Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3 : //
4 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 : //
7 : // Official repository: https://github.com/boostorg/capy
8 : //
9 :
10 : #ifndef BOOST_CAPY_EX_THREAD_POOL_HPP
11 : #define BOOST_CAPY_EX_THREAD_POOL_HPP
12 :
13 : #include <boost/capy/detail/config.hpp>
14 : #include <boost/capy/ex/any_coro.hpp>
15 : #include <boost/capy/ex/execution_context.hpp>
16 : #include <cstddef>
17 :
18 : namespace boost {
19 : namespace capy {
20 :
21 : /** A pool of threads for executing work concurrently.
22 :
23 : Use this when you need to run coroutines on multiple threads
24 : without the overhead of creating and destroying threads for
25 : each task. Work items are distributed across the pool using
26 : a shared queue.
27 :
28 : @par Thread Safety
29 : Distinct objects: Safe.
30 : Shared objects: Unsafe.
31 :
32 : @par Example
33 : @code
34 : thread_pool pool(4); // 4 worker threads
35 : auto ex = pool.get_executor();
36 : ex.post(some_coroutine);
37 : // pool destructor waits for all work to complete
38 : @endcode
39 : */
40 : class BOOST_CAPY_DECL
41 : thread_pool
42 : : public execution_context
43 : {
44 : class impl;
45 : impl* impl_;
46 :
47 : public:
48 : class executor_type;
49 :
50 : /** Destroy the thread pool.
51 :
52 : Signals all worker threads to stop, waits for them to
53 : finish, and destroys any pending work items.
54 : */
55 : ~thread_pool();
56 :
57 : /** Construct a thread pool.
58 :
59 : Creates a pool with the specified number of worker threads.
60 : If `num_threads` is zero, the number of threads is set to
61 : the hardware concurrency, or one if that cannot be determined.
62 :
63 : @param num_threads The number of worker threads, or zero
64 : for automatic selection.
65 : */
66 : explicit
67 : thread_pool(std::size_t num_threads = 0);
68 :
69 : thread_pool(thread_pool const&) = delete;
70 : thread_pool& operator=(thread_pool const&) = delete;
71 :
72 : /** Return an executor for this thread pool.
73 :
74 : @return An executor associated with this thread pool.
75 : */
76 : executor_type
77 : get_executor() const noexcept;
78 : };
79 :
80 : //------------------------------------------------------------------------------
81 :
82 : /** An executor that submits work to a thread_pool.
83 :
84 : Executors are lightweight handles that can be copied and stored.
85 : All copies refer to the same underlying thread pool.
86 :
87 : @par Thread Safety
88 : Distinct objects: Safe.
89 : Shared objects: Safe.
90 : */
91 : class thread_pool::executor_type
92 : {
93 : friend class thread_pool;
94 :
95 : thread_pool* pool_ = nullptr;
96 :
97 : explicit
98 11 : executor_type(thread_pool& pool) noexcept
99 11 : : pool_(&pool)
100 : {
101 11 : }
102 :
103 : public:
104 : /// Default construct a null executor.
105 : executor_type() = default;
106 :
107 : /// Return the underlying thread pool.
108 : thread_pool&
109 1 : context() const noexcept
110 : {
111 1 : return *pool_;
112 : }
113 :
114 : /// Notify that work has started (no-op for thread pools).
115 : void
116 2 : on_work_started() const noexcept
117 : {
118 2 : }
119 :
120 : /// Notify that work has finished (no-op for thread pools).
121 : void
122 2 : on_work_finished() const noexcept
123 : {
124 2 : }
125 :
126 : /** Submit a coroutine for execution.
127 :
128 : Posts the coroutine to the thread pool and returns
129 : immediately. The caller should suspend after calling
130 : this function.
131 :
132 : @param h The coroutine handle to execute.
133 :
134 : @return A noop coroutine handle to resume.
135 : */
136 : any_coro
137 1 : dispatch(any_coro h) const
138 : {
139 1 : post(h);
140 1 : return std::noop_coroutine();
141 : }
142 :
143 : /** Post a coroutine to the thread pool.
144 :
145 : The coroutine will be resumed on one of the pool's
146 : worker threads.
147 :
148 : @param h The coroutine handle to execute.
149 : */
150 : BOOST_CAPY_DECL
151 : void
152 : post(any_coro h) const;
153 :
154 : /** Defer a coroutine to the thread pool.
155 :
156 : Equivalent to post() for thread pools.
157 :
158 : @param h The coroutine handle to execute.
159 : */
160 : void
161 1 : defer(any_coro h) const
162 : {
163 1 : post(h);
164 1 : }
165 :
166 : /// Return true if two executors refer to the same thread pool.
167 : bool
168 3 : operator==(executor_type const& other) const noexcept
169 : {
170 3 : return pool_ == other.pool_;
171 : }
172 : };
173 :
174 : //------------------------------------------------------------------------------
175 :
176 : inline
177 : auto
178 11 : thread_pool::
179 : get_executor() const noexcept ->
180 : executor_type
181 : {
182 11 : return executor_type(const_cast<thread_pool&>(*this));
183 : }
184 :
185 : } // capy
186 : } // boost
187 :
188 : #endif
|