Jes*_*Jes 5 c++ concurrency lambda
我正在实现一个push_back
在可调用对象上有一个方法的线程池.但是我在使用lambda技巧将打包的任务移动到函数对象时遇到错误.
class Threadpool {
public:
// ...
::std::deque <::std::function<void()>> _work_queue;
::std::mutex _work_queue_mutex;
::std::condition_variable _worker_signal;
template <typename CallableT>
::std::future<::std::result_of_t<CallableT()>> push_back(CallableT&&);
}
template<typename CallableT>
::std::future<::std::result_of_t<CallableT()>> Threadpool::push_back(CallableT&& callable) {
::std::packaged_task<::std::result_of_t<CallableT()>()> task (::std::move(callable));
auto fu = task.get_future();
{
::std::unique_lock<::std::mutex> locker(_work_queue_mutex);
// COMPILE ERROR
_work_queue.emplace_back([task=::std::move(task)] () { task(); })
}
_worker_signal.notify_one();
return fu;
}
Threadpool pool;
pool.emplace_back( []() { ::std::cout << "hello\n"; } );
Run Code Online (Sandbox Code Playgroud)
编译器抱怨了emplace_back
由error: no match for call to '(const std::packaged_task<void()>) ()' _work_queue.emplace_back([task=::std::move(task)]() { task(); });
我不明白发生了什么错误的,因为据我所知packaged_task
是唯一可移动的,我通过移动捕获任务.
你的例子有两个问题。
确实,std::packaged_task
只是可移动的,所以[task=std::move(task)]
是正确的。但最重要的std::packaged_task::operator()
是需要非const
对象:https://en.cppreference.com/w/cpp/thread/packaged_task/operator()
因此 lambda 必须定义为mutable
允许使用task()
:
[task=std::move(task)] () mutable { task(); };
Run Code Online (Sandbox Code Playgroud)
但即便如此,lambda 对象只能移动,不可复制,同时std::function
需要一个可复制的对象:https ://en.cppreference.com/w/cpp/utility/functions/function
因此,解决方案之一是将 包装packaged_task
在可复制的智能指针中,如下所示:
#include <mutex>
#include <deque>
#include <functional>
#include <condition_variable>
#include <future>
#include <iostream>
#include <type_traits>
class Threadpool
{
public:
// ...
std::deque <std::function<void()>> _work_queue;
std::mutex _work_queue_mutex;
std::condition_variable _worker_signal;
template <typename CallableT>
std::future<std::result_of_t<CallableT()>> push_back(CallableT&&);
};
template<typename CallableT>
std::future<std::result_of_t<CallableT()>> Threadpool::push_back(CallableT&& callable)
{
auto task = std::make_shared<std::packaged_task<std::result_of_t<CallableT()>()>>( std::move(callable) );
auto fu = task->get_future();
{
std::unique_lock<std::mutex> locker(_work_queue_mutex);
_work_queue.emplace_back([task]() { (*task)(); });
}
_worker_signal.notify_one();
return fu;
};
int main()
{
Threadpool pool;
pool.push_back( []() { std::cout << "hello\n"; } );
}
Run Code Online (Sandbox Code Playgroud)
演示: https: //gcc.godbolt.org/z/aEfvo7Mhz