Mar*_*cký 5 c++ multithreading future packaged-task c++11
我正在分析以下代码片段,并试图详细了解它:
template<typename FUNCTION, typename... ARGUMENTS>
auto ThreadPool::add( FUNCTION&& Function, ARGUMENTS&&... Arguments ) -> std::future<typename std::result_of<FUNCTION(ARGUMENTS...)>::type>
{
using PackedTask = std::packaged_task<typename std::result_of<FUNCTION(ARGUMENTS...)>::type()>;
auto task = std::make_shared<PackedTask>(std::bind(std::forward<FUNCTION>(Function), std::forward<ARGUMENTS>(Arguments)...));
// get the future to return later
auto ret = task->get_future();
{
std::lock_guard<std::mutex> lock{jobsMutex};
jobs.emplace([task]() { (*task)(); });
}
// let a waiting thread know there is an available job
jobsAvailable.notify_one();
return ret;
}
Run Code Online (Sandbox Code Playgroud)
我对此几乎没有任何疑问std::packaged_task
.
正如可以在看到add(...)
方法体,实例std::packaged_task
- task
是范围与方法执行结束时结束局部变量.返回值ret
的std::future
类型由复制返回.的值ret
被给予了的task
(这是本地).所以一旦方法执行完成,task
超出范围,所以我希望返回的连接的std :: future实例变得无效,我的理解是否正确?
在执行该方法期间,将在线程中执行的任务方法被置于其中std::queue<Job> jobs
.为什么只有指针operator()
的std::packaged_task
持有的参考Function
在举行给出方法参数std::queue
?我希望直接存储std::packaged_task
以保存对正在创建的实例的引用...?
无论如何,源代码片段来自ThreadPool实现,可以在这里找到https://github.com/dabbertorres/ThreadPool,似乎完全正常工作.所以我认为这是正确的,但遗憾的是我并不完全清楚...如果有人能够解释这些东西的运作方式,我会很高兴的...
非常感谢愿意提供帮助的任何人.干杯马丁
正如您在 add(...) 方法体中看到的, std::packaged_task - task 的实例是局部变量,其作用域随着方法执行结束而结束。
是的,它是 的局部变量std::shared_ptr<PackedTask>
。当它超出范围时,它将引用计数减 1。如果新的引用计数为 0,它将删除它指向的对象。幸运的是,jobs
持有该共享指针的副本,以便指向的对象保持活动状态。
std::future类型的返回值ret是通过copy返回的。
不完全是。更有可能是ret
通过移动而不是通过复制返回。
该任务超出了范围,因此我希望返回的连接的 std::future 实例变得无效,我的理解正确吗?
再次,task
是共享指针。队列jobs
使其保持活动状态,并可能ret
保存该共享指针的另一个副本(以实际提取 的结果task
)。因此,只要任务在队列中并且有人持有该结果的未来,任何事情都不会变得无效。
我希望直接存储 std::packaged_task 以便保存对正在创建的实例的引用......?
确实,它可以直接存储std::packaged_task
。我的猜测是这个库的作者不想弄乱不可复制/不可移动的函子。如果 的结果std::bind
不可复制且不可移动,则您无法真正将其移动std::packaged_task
到队列中。使用共享指针解决了这个问题,因为您不复制/移动 packaged_task 本身,而只复制/移动指针。但是,您可以将任务对象直接构建到队列中,但在持有锁下执行此操作并不是一个好的做法。
不过,我确实同意,也许迁移task
到 lambda 比复制它更有效。