GCC Code Coverage Report


Directory: ./
File: libs/capy/include/boost/capy/ex/thread_pool.hpp
Date: 2026-01-15 20:40:20
Exec Total Coverage
Lines: 15 15 100.0%
Functions: 6 6 100.0%
Branches: 0 0 -%

Line Branch Exec Source
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 thread pool execution context for running work asynchronously.
22
23 This class provides a pool of worker threads that execute
24 submitted work items. It inherits from `execution_context`,
25 providing service management and a nested `executor_type`
26 that satisfies the `capy::executor` concept.
27
28 Work is submitted via the executor obtained from `get_executor()`.
29 The executor's `post()`, `dispatch()`, and `defer()` functions
30 queue coroutines for execution on pool threads.
31
32 @par Thread Safety
33 All member functions may be called concurrently.
34
35 @par Example
36 @code
37 thread_pool pool(4); // 4 worker threads
38 auto ex = pool.get_executor();
39
40 // Post a coroutine for execution
41 ex.post(my_coroutine_handle);
42 @endcode
43
44 @see execution_context, executor
45 */
46 class BOOST_CAPY_DECL
47 thread_pool
48 : public execution_context
49 {
50 class impl;
51 impl* impl_;
52
53 public:
54 class executor_type;
55
56 /** Destructor.
57
58 Signals all threads to stop and waits for them to complete.
59 Calls `shutdown()` and `destroy()` to clean up services.
60 */
61 ~thread_pool();
62
63 /** Construct a thread pool.
64
65 @param num_threads The number of worker threads to create.
66 If zero, defaults to the hardware concurrency.
67 */
68 explicit
69 thread_pool(std::size_t num_threads = 0);
70
71 thread_pool(thread_pool const&) = delete;
72 thread_pool& operator=(thread_pool const&) = delete;
73
74 /** Return an executor for this thread pool.
75
76 The returned executor can be used to post work items
77 to this thread pool.
78
79 @return An executor associated with this thread pool.
80 */
81 executor_type
82 get_executor() const noexcept;
83 };
84
85 //------------------------------------------------------------------------------
86
87 /** An executor for dispatching work to a thread_pool.
88
89 The executor provides the interface for posting work items
90 to the associated thread_pool. It satisfies the `capy::executor`
91 concept.
92
93 Executors are lightweight handles that can be copied and compared
94 for equality. Two executors compare equal if they refer to the
95 same thread_pool.
96
97 @par Thread Safety
98 Distinct objects: Safe.@n
99 Shared objects: Safe.
100 */
101 class thread_pool::executor_type
102 {
103 friend class thread_pool;
104
105 thread_pool* pool_ = nullptr;
106
107 explicit
108 11 executor_type(thread_pool& pool) noexcept
109 11 : pool_(&pool)
110 {
111 11 }
112
113 public:
114 /** Default constructor.
115
116 Constructs an executor not associated with any thread_pool.
117 */
118 executor_type() = default;
119
120 /** Return a reference to the associated execution context.
121
122 @return Reference to the thread_pool.
123 */
124 thread_pool&
125 1 context() const noexcept
126 {
127 1 return *pool_;
128 }
129
130 /** Informs the executor that work is beginning.
131
132 Must be paired with `on_work_finished()`.
133 */
134 BOOST_CAPY_DECL
135 void
136 on_work_started() const noexcept;
137
138 /** Informs the executor that work has completed.
139
140 @par Preconditions
141 A preceding call to `on_work_started()` on an equal executor.
142 */
143 BOOST_CAPY_DECL
144 void
145 on_work_finished() const noexcept;
146
147 /** Dispatch a coroutine handle.
148
149 For thread_pool, dispatch always posts the work since
150 the calling thread is never "inside" the pool's run loop.
151
152 @param h The coroutine handle to dispatch.
153
154 @return `std::noop_coroutine()` since work is always posted.
155 */
156 any_coro
157 1 dispatch(any_coro h) const
158 {
159 1 post(h);
160 1 return std::noop_coroutine();
161 }
162
163 /** Post a coroutine for deferred execution.
164
165 The coroutine will be resumed on one of the pool's
166 worker threads.
167
168 @param h The coroutine handle to post.
169 */
170 BOOST_CAPY_DECL
171 void
172 post(any_coro h) const;
173
174 /** Queue a coroutine for deferred execution.
175
176 This is semantically identical to `post`, but conveys that
177 `h` is a continuation of the current call context.
178
179 @param h The coroutine handle to defer.
180 */
181 void
182 1 defer(any_coro h) const
183 {
184 1 post(h);
185 1 }
186
187 /** Compare two executors for equality.
188
189 @return `true` if both executors refer to the same thread_pool.
190 */
191 bool
192 3 operator==(executor_type const& other) const noexcept
193 {
194 3 return pool_ == other.pool_;
195 }
196 };
197
198 //------------------------------------------------------------------------------
199
200 inline
201 auto
202 11 thread_pool::
203 get_executor() const noexcept ->
204 executor_type
205 {
206 11 return executor_type(const_cast<thread_pool&>(*this));
207 }
208
209 } // capy
210 } // boost
211
212 #endif
213