libs/capy/include/boost/capy/ex/thread_pool.hpp

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