I'm working on a thread pool from the book C++ Cuncerrency in Action by Anthony Willimas
This thread pools has a submit call that take as tasks callable objects that return a value and return a std::future
handle to them, and I managed to build applications that use it.
But I can't manage to make it work with callable ojects that return void: the code won't even compile. I get these errors, all in the future
header :
error C2182: '_Get_value' : illegal use of type 'void'
error C2182: '_Val' : illegal use of type 'void'
error C2182: '_Val' : illegal use of type 'void'
error C2665: 'std::forward' : none of the 2 overloads could convert all the argument types
error C2512: 'std::_Promise<int>' : no appropriate default constructor available
The submit
call is
template<typename FunctionType>
std::future<typename std::result_of<FunctionType()>::type> submit(FunctionType f){
typedef typename std::result_of<FunctionType()>::type result_type;
std::packaged_task<result_type()> task(std::move(f));
std::future<result_type> res(task.get_future());
work_queue.push(std::move(task));
return res;
}
If I comment this line
work_queue.push(std::move(task));
the code compiles. So I think that the problem is "there"...
The work_queue
is delcared as
threadsafe_queue<function_wrapper> work_queue;
where threadsafe_queue
is
template<typename T>
class threadsafe_queue{
private:
mutable std::mutex mut;
std::queue<std::shared_ptr<T> > data_queue;
std::condition_variable data_cond;
public:
threadsafe_queue(){}
void push(T new_value){
std::shared_ptr<T> data(
std::make_shared<T>(std::move(new_value)));
std::lock_guard<std::mutex> lk(mut);
data_queue.push(data);
data_cond.notify_one();
}
//[...]
}
and threadsafe_queue
class function_wrapper{
struct impl_base {
virtual void call()=0;
virtual ~impl_base() {}
};
std::unique_ptr<impl_base> impl;
template<typename F>
struct impl_type: impl_base{
F f;
impl_type(F&& f_): f(std::move(f_)) {}
void call() { f(); }
};
public:
template<typename F>
function_wrapper(F&& f):impl(new impl_type<F>(std::move(f))){}
void operator()() { impl->call(); }
function_wrapper(){}
function_wrapper(function_wrapper&& other):impl(std::move(other.impl)){}
function_wrapper& operator=(function_wrapper&& other){
impl=std::move(other.impl);
return *this;
}
private:
function_wrapper(const function_wrapper&);
function_wrapper(function_wrapper&);
function_wrapper& operator=(const function_wrapper&);
};
I tried with, but I got the same errors.
template<typename FunctionType>
std::future<void> submit(FunctionType f){
std::packaged_task<void(void)> task(std::move(f));
std::future<void> res(task.get_future());
work_queue.push(std::move(task));
return res;
}