1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
|
//
// thread_pool.hpp
// ~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_THREAD_POOL_HPP
#define ASIO_THREAD_POOL_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/scheduler.hpp"
#include "asio/detail/thread_group.hpp"
#include "asio/execution_context.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
/// A simple fixed-size thread pool.
/**
* The thread pool class is an execution context where functions are permitted
* to run on one of a fixed number of threads.
*
* @par Submitting tasks to the pool
*
* To submit functions to the io_context, use the @ref asio::dispatch,
* @ref asio::post or @ref asio::defer free functions.
*
* For example:
*
* @code void my_task()
* {
* ...
* }
*
* ...
*
* // Launch the pool with four threads.
* asio::thread_pool pool(4);
*
* // Submit a function to the pool.
* asio::post(pool, my_task);
*
* // Submit a lambda object to the pool.
* asio::post(pool,
* []()
* {
* ...
* });
*
* // Wait for all tasks in the pool to complete.
* pool.join(); @endcode
*/
class thread_pool
: public execution_context
{
public:
class executor_type;
/// Constructs a pool with an automatically determined number of threads.
ASIO_DECL thread_pool();
/// Constructs a pool with a specified number of threads.
ASIO_DECL thread_pool(std::size_t num_threads);
/// Destructor.
/**
* Automatically stops and joins the pool, if not explicitly done beforehand.
*/
ASIO_DECL ~thread_pool();
/// Obtains the executor associated with the pool.
executor_type get_executor() ASIO_NOEXCEPT;
/// Stops the threads.
/**
* This function stops the threads as soon as possible. As a result of calling
* @c stop(), pending function objects may be never be invoked.
*/
ASIO_DECL void stop();
/// Joins the threads.
/**
* This function blocks until the threads in the pool have completed. If @c
* stop() is not called prior to @c join(), the @c join() call will wait
* until the pool has no more outstanding work.
*/
ASIO_DECL void join();
private:
friend class executor_type;
struct thread_function;
// The underlying scheduler.
detail::scheduler& scheduler_;
// The threads in the pool.
detail::thread_group threads_;
};
/// Executor used to submit functions to a thread pool.
class thread_pool::executor_type
{
public:
/// Obtain the underlying execution context.
thread_pool& context() const ASIO_NOEXCEPT;
/// Inform the thread pool that it has some outstanding work to do.
/**
* This function is used to inform the thread pool that some work has begun.
* This ensures that the thread pool's join() function will not return while
* the work is underway.
*/
void on_work_started() const ASIO_NOEXCEPT;
/// Inform the thread pool that some work is no longer outstanding.
/**
* This function is used to inform the thread pool that some work has
* finished. Once the count of unfinished work reaches zero, the thread
* pool's join() function is permitted to exit.
*/
void on_work_finished() const ASIO_NOEXCEPT;
/// Request the thread pool to invoke the given function object.
/**
* This function is used to ask the thread pool to execute the given function
* object. If the current thread belongs to the pool, @c dispatch() executes
* the function before returning. Otherwise, the function will be scheduled
* to run on the thread pool.
*
* @param f The function object to be called. The executor will make
* a copy of the handler object as required. The function signature of the
* function object must be: @code void function(); @endcode
*
* @param a An allocator that may be used by the executor to allocate the
* internal storage needed for function invocation.
*/
template <typename Function, typename Allocator>
void dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
/// Request the thread pool to invoke the given function object.
/**
* This function is used to ask the thread pool to execute the given function
* object. The function object will never be executed inside @c post().
* Instead, it will be scheduled to run on the thread pool.
*
* @param f The function object to be called. The executor will make
* a copy of the handler object as required. The function signature of the
* function object must be: @code void function(); @endcode
*
* @param a An allocator that may be used by the executor to allocate the
* internal storage needed for function invocation.
*/
template <typename Function, typename Allocator>
void post(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
/// Request the thread pool to invoke the given function object.
/**
* This function is used to ask the thread pool to execute the given function
* object. The function object will never be executed inside @c defer().
* Instead, it will be scheduled to run on the thread pool.
*
* If the current thread belongs to the thread pool, @c defer() will delay
* scheduling the function object until the current thread returns control to
* the pool.
*
* @param f The function object to be called. The executor will make
* a copy of the handler object as required. The function signature of the
* function object must be: @code void function(); @endcode
*
* @param a An allocator that may be used by the executor to allocate the
* internal storage needed for function invocation.
*/
template <typename Function, typename Allocator>
void defer(ASIO_MOVE_ARG(Function) f, const Allocator& a) const;
/// Determine whether the thread pool is running in the current thread.
/**
* @return @c true if the current thread belongs to the pool. Otherwise
* returns @c false.
*/
bool running_in_this_thread() const ASIO_NOEXCEPT;
/// Compare two executors for equality.
/**
* Two executors are equal if they refer to the same underlying thread pool.
*/
friend bool operator==(const executor_type& a,
const executor_type& b) ASIO_NOEXCEPT
{
return &a.pool_ == &b.pool_;
}
/// Compare two executors for inequality.
/**
* Two executors are equal if they refer to the same underlying thread pool.
*/
friend bool operator!=(const executor_type& a,
const executor_type& b) ASIO_NOEXCEPT
{
return &a.pool_ != &b.pool_;
}
private:
friend class thread_pool;
// Constructor.
explicit executor_type(thread_pool& p) : pool_(p) {}
// The underlying thread pool.
thread_pool& pool_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#include "asio/impl/thread_pool.hpp"
#if defined(ASIO_HEADER_ONLY)
# include "asio/impl/thread_pool.ipp"
#endif // defined(ASIO_HEADER_ONLY)
#endif // ASIO_THREAD_POOL_HPP
|