Skip to content

Commit 07b95ee

Browse files
committedSep 12, 2016
Use concepts to accept arbitrary callable.
Need to refactor better. But doing so might require constexpr if to avoid having so many specializations.
1 parent 5ea01d0 commit 07b95ee

File tree

3 files changed

+74
-85
lines changed

3 files changed

+74
-85
lines changed
 

‎.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.swp
2+
a.out

‎test.cpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ void test_void_void(){
2525
thread_pool p(num_threads);
2626
vector<future<void>> f;
2727
for(int i = 10000000;i < 20000000;i++)
28-
f.emplace_back(p.async(function<void()>(func_void_void)));
28+
f.emplace_back(p.async(func_void_void));
2929
for(auto i = f.begin();i != f.end();i++)
3030
i->get();
3131
}
@@ -44,7 +44,7 @@ void test_void_int(){
4444
thread_pool p(num_threads);
4545
vector<future<void>> f;
4646
for(int i = 10000000;i < 20000000;i++)
47-
f.emplace_back(p.async<int>(function<void(int)>(func_void_int), i));
47+
f.emplace_back(p.async(func_void_int, i));
4848
for(auto i = f.begin();i != f.end();i++)
4949
i->get();
5050
}
@@ -57,7 +57,7 @@ void test_int_void(){
5757
thread_pool p(num_threads);
5858
vector<future<int>> f;
5959
for(int i = 100000;i < 1000000;i++)
60-
f.emplace_back(p.async(function<int()>(func_int_void)));
60+
f.emplace_back(p.async<decltype(func_int_void), int>(func_int_void));
6161
for(auto i = f.begin();i != f.end();i++)
6262
cout << i->get() << endl;
6363
}
@@ -77,7 +77,7 @@ void test_bool_int(){
7777
int n = 100000;
7878
int max = 10 * n;
7979
for(int i = n;i < max;i++)
80-
f.emplace_back(p.async(function<bool(int)>(func_bool_int), i));
80+
f.emplace_back(p.async<decltype(func_bool_int), bool, int>(func_bool_int, i));
8181
for(auto i = f.begin();i != f.end();i++, n++)
8282
cout << n << ": " << i->get() << endl;
8383
}
@@ -91,8 +91,8 @@ void test_void_int_int() {
9191
vector<future<int>> f;
9292
for(int i = 1;i < 100;i++) {
9393
for(int j = 1;j < 100;j++) {
94-
f.emplace_back(p.async<int, int>(
95-
function<int(int, int)>(func_int_int_int), i, j));
94+
f.emplace_back(p.async<decltype(func_int_int_int), int, int, int>(
95+
func_int_int_int, i, j));
9696
}
9797
}
9898
for(auto i = f.begin();i != f.end();i++)

‎thread_pool.hpp

+66-79
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
#define THREAD_POOL_HPP
33

44
#include <atomic>
5-
#include <csetjmp>
65
#include <functional>
76
#include <future>
87
#include <list>
@@ -16,6 +15,11 @@
1615

1716
using std::experimental::optional;
1817

18+
template<typename Fn, typename Ret, typename... Args>
19+
concept bool Callable = requires(Fn f, Args... args) {
20+
{ f(args...) } -> Ret;
21+
};
22+
1923
class priority_task {
2024
public:
2125
priority_task(std::function<void()> work, int priority = 0) :
@@ -59,11 +63,10 @@ class base_thread_pool{
5963
*
6064
* @return the future used to wait on the task and get the result
6165
*/
62-
template<typename Ret, typename... Args>
66+
template<typename Fn, typename Ret, typename... Args>
67+
requires Callable<Fn, Ret, Args...>
6368
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){
6770
std::promise<Ret> *p = new std::promise<Ret>;
6871

6972
// Create a function to package as a task.
@@ -92,11 +95,10 @@ class base_thread_pool{
9295
*
9396
* @return the future used to wait on the task and get the result
9497
*/
95-
template<typename Ret>
98+
template<typename Fn, typename Ret>
99+
requires Callable<Fn, Ret>
96100
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){
100102
std::promise<Ret> *p = new std::promise<Ret>;
101103

102104
// Create a function to package as a task.
@@ -126,11 +128,10 @@ class base_thread_pool{
126128
*
127129
* @return the future used to wait on the task
128130
*/
129-
template<typename... Args>
131+
template<typename Fn, typename... Args>
132+
requires Callable<Fn, void, Args...>
130133
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){
134135
std::promise<void> *p = new std::promise<void>;
135136

136137
// Create a function to package as a task.
@@ -158,10 +159,10 @@ class base_thread_pool{
158159
*
159160
* @return the future used to wait on the task
160161
*/
162+
template<typename Fn>
163+
requires Callable<Fn, void>
161164
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){
165166
std::promise<void> *p = new std::promise<void>;
166167

167168
// Create a function to package as a task.
@@ -286,14 +287,10 @@ class thread_pool : public base_thread_pool<std::future<void>>{
286287
*
287288
* @return the future used to wait on the task and get the result
288289
*/
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)));
297294
}
298295

299296
/**
@@ -304,14 +301,10 @@ class thread_pool : public base_thread_pool<std::future<void>>{
304301
*
305302
* @return the future used to wait on the task and get the result
306303
*/
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)));
315308
}
316309

317310
/**
@@ -323,14 +316,11 @@ class thread_pool : public base_thread_pool<std::future<void>>{
323316
*
324317
* @return the future used to wait on the task
325318
*/
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)));
334324
}
335325

336326
/**
@@ -341,21 +331,25 @@ class thread_pool : public base_thread_pool<std::future<void>>{
341331
*
342332
* @return the future used to wait on the task
343333
*/
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)));
351338
}
352339

353340
protected:
354341
virtual optional<std::future<void>> get_task() override;
355342
virtual void handle_task(std::future<void>) override;
356-
357343
private:
358344
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+
}
359353
};
360354

361355
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
373367
*
374368
* @return the future used to wait on the task and get the result
375369
*/
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,
378372
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)));
385375
}
386376

387377
/**
@@ -393,14 +383,10 @@ class priority_thread_pool : public base_thread_pool<std::shared_ptr<priority_ta
393383
*
394384
* @return the future used to wait on the task and get the result
395385
*/
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)));
404390
}
405391

406392
/**
@@ -413,14 +399,10 @@ class priority_thread_pool : public base_thread_pool<std::shared_ptr<priority_ta
413399
*
414400
* @return the future used to wait on the task
415401
*/
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)));
424406
}
425407

426408
/**
@@ -432,13 +414,10 @@ class priority_thread_pool : public base_thread_pool<std::shared_ptr<priority_ta
432414
*
433415
* @return the future used to wait on the task
434416
*/
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)));
442421
}
443422

444423
/// 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
448427
virtual optional<std::shared_ptr<priority_task>> get_task() override;
449428
virtual void handle_task(std::shared_ptr<priority_task>) override;
450429

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+
451438
private:
452439
std::priority_queue<std::shared_ptr<priority_task>> tasks;
453440
};

0 commit comments

Comments
 (0)
Please sign in to comment.