-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathpool.hpp
More file actions
247 lines (220 loc) · 7.62 KB
/
pool.hpp
File metadata and controls
247 lines (220 loc) · 7.62 KB
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
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
/* kate: space-indent off; remove-trailing-spaces all; indent-width 4; */
/*!
* \file pool.hpp
* \author ichramm
* \date June 30, 2012, 2:43 AM
*
* Thread Pool class declaration
*/
#ifndef threadpool_pool_hpp__
#define threadpool_pool_hpp__
#include <boost/function.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/enable_shared_from_this.hpp>
#if _MSC_VER > 1000
# pragma warning(push)
# pragma warning(disable: 4251) // class 'T' needs to have dll-interface...
#endif
#ifdef _WIN32
# ifdef THREADPOOL_EXPORTS
# define THREADPOOL_API __declspec(dllexport)
# else
# define THREADPOOL_API __declspec(dllimport)
# endif
#else
# define THREADPOOL_API
#endif
namespace threadpool
{
/*!
* Base class for task objects
* Use \c boost::bind to create objects of this type
*/
typedef boost::function0<void> task_type;
/*!
* Scheduling function will return one of these values
*/
enum schedule_result
{
/*!
* The task was correctly scheduled
*/
schedule_result_ok,
/*!
* The pool is stopping and cannot accept more tasks
*/
schedule_result_err_down,
/*!
* The pool is too busy to accept another task
* This may happens only if all the following conditions are met:
* \li All threads are busy
* \li Maximum number of threads has been reached (i.e. Cannot crate more threads)
* \li Task queue is full
*
* \note This value is not in use at the moment because the task queue has no capacity limit.
*/
schedule_result_err_busy
};
/*!
* These options control how the pool should behave on destruction
*/
enum shutdown_option
{
/*! The pool stops immediately, all tasks are canceled */
shutdown_option_cancel_tasks,
/*! The pool will wait until all tasks are complete before stopping */
shutdown_option_wait_for_tasks
};
/*!
* Thread pool class
*
* This class implements a smart thread pool, smart in the sense it
* can increase or decrease the number of threads in the pool depending
* on how the load is.
*
* Pending tasks are stored in a FIFO queue, each thread in the pool pops tasks
* from the queue and executes them.
*
* Tasks can also be scheduled for execution in a later time, without actually
* blocking a thread.
* These tasks are queued the same way as standard tasks, but they store the time
* information needed to know when to execute them. Anytime a thread dequeues a task of
* this type, the time information is checked and if the current time is still less than
* the requested execution time then the task is sent back to the queue.
*
* This class uses an additional thread to monitor pool status, so don't be scared if
* you your favorite monitoring tool shows an extra thread around there.
* The pool monitor uses a soft-timeout to ensure the pool is resized when it's really
* needed. By default the monitor waits 100 ms before adding more threads to the pool.
* Something similar happens when it has to remove threads from the pool, but
* this time the timeout is longer because we do not want to delete threads if
* we will probably need them later.
*
* \note Even when this class uses an extra thread to monitor pool status, it never
* creates more than \p max_threads threads.
*
* \note The pool increases it's size by a factor of 1.5 and decreases it by a factor of 2.0
*
* \note The pool is considered idle when over 75% of threads are idle
*
* \note The pool is considered overloaded when all threads are busy and there is at
* least one pending task in the queue for not less than 2 milliseconds.
*/
class THREADPOOL_API pool
: public boost::enable_shared_from_this<pool>
{
public:
/*!
* Creates the threadpool, upper and lower bounds can be specified
*
* \param min_threads Minimum threads to have in the pool. If this parameter is equal
* to -1 the pool will create twice the number of processors (or HT cores) on the
* host computer as reported by \c boost::thread::hardware_concurrency().
*
* \param max_threads Maximum threads the pool can create.
*
* \param timeout_add_threads_ms Specifies how much time we wait until resizing the
* pool when there are pending tasks but all the threads are busy.
*
* \param timeout_del_threads_ms Milliseconds to wait until remove threads from the
* pool when the load is too low.
*
* \param on_shutdown Specifies what to do with pending tasks when the pool is being
* destroyed. \see shutdown_option.
*
* \pre \code max_threads >= min_threads \endcode
*
* The constructor creates exactly \code min_threads + 1 \endcode threads, the
* extra thread is for monitoring the pool status.
*
* \note When \p on_shutdown is set to \c shutdown_option_wait_for_tasks, the pool
* only waits for the tasks that were queued for immediate execution, all future
* tasks are canceled in order to avoid waiting too long.
*/
pool (
unsigned int min_threads = -1,
unsigned int max_threads = 1000,
unsigned int timeout_add_threads_ms = 100,
unsigned int timeout_del_threads_ms = 300000,
shutdown_option on_shutdown = shutdown_option_wait_for_tasks
);
/*!
* Calls \c stop() it wasn't called already, destroys \c *this
*/
~pool();
/*!
* Stops the pool and subsequently destroys all threads. Checks for
* the \c shutdown_option specified in the constructor in order to wait
* or cancel pending tasks.
*
* \remarks This function should be called only once
*
* \remarks Tasks scheduled for execution in the future will be canceled
* no matter which \c shutdown_option is set.
*/
void stop();
/*!
* Queue an task for immediate execution.
*
* The task is going to be executed as soon as a thread
* is available, if there are no available threads the monitor will create them
*/
schedule_result schedule(const task_type& task);
/*!
* Queue a task for execution when the time as reported
* by \c boost::get_system_time() would be equal to or later
* than the specified \p abs_time
*
* \note When in very heavy load, the task could not be executed exactly when
* it was requested to.
*/
schedule_result schedule(const task_type& task, const boost::system_time& abs_time);
/*!
* Queue a task for execution after the period of time indicated
* by the \p rel_time argument has elapsed
*
* \note When in very heavy load, the task could not be executed exactly when
* it was requested to.
*/
schedule_result schedule(const task_type& task, const boost::posix_time::time_duration& rel_time);
/*!
* \return The number of active tasks in the pool, aka the number of threads
* executing user requested tasks
*/
unsigned int active_tasks() const;
/*!
* \return The number of tasks waiting for an available thread
*
* If this number gets too high for a long time you should be worried
*/
unsigned int pending_tasks() const;
/*!
* \return The number of tasks that are queued but not ready
* to be executed
*/
unsigned int future_tasks() const;
/*!
* \return The number of threads in the pool, it's a number
* between \c min_threads and \c max_threads (see constructor)
*/
unsigned int pool_size() const;
protected:
/*!
* Called when the pool is resized
*
* \param delta Specifies how many threads where added or removed from the pool
*/
virtual void pool_size_changed( int /*delta*/ )
{ }
private:
struct impl;
boost::scoped_ptr<impl> pimpl; // pimpl idiom
pool( const pool& );
const pool& operator=( const pool& );
};
} // namespace threadpool
#if _MSC_VER > 1000
# pragma warning(pop)
#endif
#endif // threadpool_pool_hpp__