2
2
#define THREAD_POOL_HPP
3
3
4
4
#include < atomic>
5
- #include < csetjmp>
6
5
#include < functional>
7
6
#include < future>
8
7
#include < list>
16
15
17
16
using std::experimental::optional;
18
17
18
+ template <typename Fn, typename Ret, typename ... Args>
19
+ concept bool Callable = requires(Fn f, Args... args) {
20
+ { f (args...) } -> Ret;
21
+ };
22
+
19
23
class priority_task {
20
24
public:
21
25
priority_task (std::function<void ()> work, int priority = 0 ) :
@@ -59,11 +63,10 @@ class base_thread_pool{
59
63
*
60
64
* @return the future used to wait on the task and get the result
61
65
*/
62
- template <typename Ret, typename ... Args>
66
+ template <typename Fn, typename Ret, typename ... Args>
67
+ requires Callable<Fn, Ret, Args...>
63
68
std::pair<std::function<void ()>,std::future<Ret>>
64
- package (std::function<Ret(Args...)> f, Args... args){
65
- typedef std::function<Ret (Args...)> F;
66
-
69
+ package (Fn f, Args... args){
67
70
std::promise<Ret> *p = new std::promise<Ret>;
68
71
69
72
// Create a function to package as a task.
@@ -92,11 +95,10 @@ class base_thread_pool{
92
95
*
93
96
* @return the future used to wait on the task and get the result
94
97
*/
95
- template <typename Ret>
98
+ template <typename Fn, typename Ret>
99
+ requires Callable<Fn, Ret>
96
100
std::pair<std::function<void ()>,std::future<Ret>>
97
- package (std::function<Ret()> f){
98
- typedef std::function<Ret ()> F;
99
-
101
+ package (Fn f){
100
102
std::promise<Ret> *p = new std::promise<Ret>;
101
103
102
104
// Create a function to package as a task.
@@ -126,11 +128,10 @@ class base_thread_pool{
126
128
*
127
129
* @return the future used to wait on the task
128
130
*/
129
- template <typename ... Args>
131
+ template <typename Fn, typename ... Args>
132
+ requires Callable<Fn, void , Args...>
130
133
std::pair<std::function<void ()>,std::future<void >>
131
- package (std::function<void (Args...)> f, Args... args){
132
- typedef std::function<void (Args...)> F;
133
-
134
+ package (Fn f, Args... args){
134
135
std::promise<void > *p = new std::promise<void >;
135
136
136
137
// Create a function to package as a task.
@@ -158,10 +159,10 @@ class base_thread_pool{
158
159
*
159
160
* @return the future used to wait on the task
160
161
*/
162
+ template <typename Fn>
163
+ requires Callable<Fn, void >
161
164
std::pair<std::function<void ()>,std::future<void >>
162
- package (std::function<void ()> f){
163
- typedef std::function<void ()> F;
164
-
165
+ package (Fn f){
165
166
std::promise<void > *p = new std::promise<void >;
166
167
167
168
// Create a function to package as a task.
@@ -286,14 +287,10 @@ class thread_pool : public base_thread_pool<std::future<void>>{
286
287
*
287
288
* @return the future used to wait on the task and get the result
288
289
*/
289
- template <typename Ret, typename ... Args>
290
- std::future<Ret> async (std::function<Ret(Args...)> f, Args... args){
291
- auto p = package (f, args...);
292
- auto t = std::async (std::launch::deferred, p.first );
293
- task_mutex.lock ();
294
- tasks.emplace (std::move (t));
295
- task_mutex.unlock ();
296
- return std::move (p.second );
290
+ template <typename Fn, typename Ret, typename ... Args>
291
+ std::future<Ret> async (Fn f, Args... args){
292
+ auto p = package<Fn, Ret, Args...>(f, args...);
293
+ return std::move (add_task_helper (std::move (p)));
297
294
}
298
295
299
296
/* *
@@ -304,14 +301,10 @@ class thread_pool : public base_thread_pool<std::future<void>>{
304
301
*
305
302
* @return the future used to wait on the task and get the result
306
303
*/
307
- template <typename Ret>
308
- std::future<Ret> async (std::function<Ret()> f){
309
- auto p = package (f);
310
- auto t = std::async (std::launch::deferred, p.first );
311
- task_mutex.lock ();
312
- tasks.emplace (std::move (t));
313
- task_mutex.unlock ();
314
- return std::move (p.second );
304
+ template <typename Fn, typename Ret>
305
+ std::future<Ret> async (Fn f){
306
+ auto p = package<Fn, decltype (f ())>(f);
307
+ return std::move (add_task_helper (std::move (p)));
315
308
}
316
309
317
310
/* *
@@ -323,14 +316,11 @@ class thread_pool : public base_thread_pool<std::future<void>>{
323
316
*
324
317
* @return the future used to wait on the task
325
318
*/
326
- template <typename ... Args>
327
- std::future<void > async (std::function<void (Args...)> f, Args... args){
328
- auto p = package<Args...>(f, args...);
329
- auto t = std::async (std::launch::deferred, p.first );
330
- task_mutex.lock ();
331
- tasks.emplace (std::move (t));
332
- task_mutex.unlock ();
333
- return std::move (p.second );
319
+ template <typename Fn, typename ... Args>
320
+ requires Callable<Fn, void , Args...>
321
+ std::future<void > async (Fn f, Args... args){
322
+ auto p = package<Fn, Args...>(f, args...);
323
+ return std::move (add_task_helper (std::move (p)));
334
324
}
335
325
336
326
/* *
@@ -341,21 +331,25 @@ class thread_pool : public base_thread_pool<std::future<void>>{
341
331
*
342
332
* @return the future used to wait on the task
343
333
*/
344
- std::future<void > async (std::function<void ()> f){
345
- auto p = package (f);
346
- auto t = std::async (std::launch::deferred, p.first );
347
- task_mutex.lock ();
348
- tasks.emplace (std::move (t));
349
- task_mutex.unlock ();
350
- return std::move (p.second );
334
+ template <typename Fn>
335
+ std::future<void > async (Fn f){
336
+ auto p = package<Fn>(f);
337
+ return std::move (add_task_helper (std::move (p)));
351
338
}
352
339
353
340
protected:
354
341
virtual optional<std::future<void >> get_task () override ;
355
342
virtual void handle_task (std::future<void >) override ;
356
-
357
343
private:
358
344
std::queue<std::future<void >> tasks;
345
+
346
+ auto add_task_helper (auto p) {
347
+ auto t = std::async (std::launch::deferred, p.first );
348
+ task_mutex.lock ();
349
+ tasks.emplace (std::move (t));
350
+ task_mutex.unlock ();
351
+ return std::move (p.second );
352
+ }
359
353
};
360
354
361
355
class priority_thread_pool : public base_thread_pool <std::shared_ptr<priority_task>>{
@@ -373,15 +367,11 @@ class priority_thread_pool : public base_thread_pool<std::shared_ptr<priority_ta
373
367
*
374
368
* @return the future used to wait on the task and get the result
375
369
*/
376
- template <typename Ret, typename ... Args>
377
- std::future<Ret> async (int priority, std::function<Ret(Args...)> f,
370
+ template <typename Fn, typename Ret, typename ... Args>
371
+ std::future<Ret> async (int priority, Fn f,
378
372
Args... args){
379
- auto p = package (f, args...);
380
- auto t = std::shared_ptr<priority_task>(new priority_task (p.first , priority));
381
- task_mutex.lock ();
382
- tasks.emplace (t);
383
- task_mutex.unlock ();
384
- return std::move (p.second );
373
+ auto p = package<Fn, Ret, Args...>(f, args...);
374
+ return std::move (add_task_helper (priority, std::move (p)));
385
375
}
386
376
387
377
/* *
@@ -393,14 +383,10 @@ class priority_thread_pool : public base_thread_pool<std::shared_ptr<priority_ta
393
383
*
394
384
* @return the future used to wait on the task and get the result
395
385
*/
396
- template <typename Ret>
397
- std::future<Ret> async (int priority, std::function<Ret()> f){
398
- auto p = package (f);
399
- auto t = std::shared_ptr<priority_task>(new priority_task (p.first , priority));
400
- task_mutex.lock ();
401
- tasks.emplace (t);
402
- task_mutex.unlock ();
403
- return std::move (p.second );
386
+ template <typename Fn, typename Ret>
387
+ std::future<Ret> async (int priority, Fn f){
388
+ auto p = package<Fn, decltype (f ())>(f);
389
+ return std::move (add_task_helper (priority, std::move (p)));
404
390
}
405
391
406
392
/* *
@@ -413,14 +399,10 @@ class priority_thread_pool : public base_thread_pool<std::shared_ptr<priority_ta
413
399
*
414
400
* @return the future used to wait on the task
415
401
*/
416
- template <typename ... Args>
417
- std::future<void > async (int priority, std::function<void (Args...)> f, Args... args){
418
- auto p = package (f, args...);
419
- auto t = std::shared_ptr<priority_task>(new priority_task (p.first , priority));
420
- task_mutex.lock ();
421
- tasks.emplace (t);
422
- task_mutex.unlock ();
423
- return std::move (p.second );
402
+ template <typename Fn, typename ... Args>
403
+ std::future<void > async (int priority, Fn f, Args... args){
404
+ auto p = package<Fn, Args...>(f, args...);
405
+ return std::move (add_task_helper (priority, std::move (p)));
424
406
}
425
407
426
408
/* *
@@ -432,13 +414,10 @@ class priority_thread_pool : public base_thread_pool<std::shared_ptr<priority_ta
432
414
*
433
415
* @return the future used to wait on the task
434
416
*/
435
- std::future<void > async (int priority, std::function<void ()> f){
436
- auto p = package (f);
437
- auto t = std::shared_ptr<priority_task>(new priority_task (p.first , priority));
438
- task_mutex.lock ();
439
- tasks.emplace (t);
440
- task_mutex.unlock ();
441
- return std::move (p.second );
417
+ template <typename Fn>
418
+ std::future<void > async (int priority, Fn f){
419
+ auto p = package<Fn>(f);
420
+ return std::move (add_task_helper (priority, std::move (p)));
442
421
}
443
422
444
423
// / Called by tasks of this thread pool to yield.
@@ -448,6 +427,14 @@ class priority_thread_pool : public base_thread_pool<std::shared_ptr<priority_ta
448
427
virtual optional<std::shared_ptr<priority_task>> get_task () override ;
449
428
virtual void handle_task (std::shared_ptr<priority_task>) override ;
450
429
430
+ auto add_task_helper (int priority, auto p) {
431
+ auto t = std::shared_ptr<priority_task>(new priority_task (p.first , priority));
432
+ task_mutex.lock ();
433
+ tasks.emplace (t);
434
+ task_mutex.unlock ();
435
+ return std::move (p.second );
436
+ }
437
+
451
438
private:
452
439
std::priority_queue<std::shared_ptr<priority_task>> tasks;
453
440
};
0 commit comments