我正在分析以下代码片段,并试图详细了解它:
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;
}
关于std::packaged_task
我几乎没有问题。
正如您在add(...)
方法体中所看到的,std::packaged_task
- task
的实例是局部变量,其范围以方法执行结束而结束。 ret
类型的返回值std::future
由副本返回。 ret
的值来自task
(本地)。所以一旦方法执行完成,task
超出了范围,所以我希望返回的连接的std :: future实例变得无效,我的理解是否正确?
在执行方法期间,要在线程中执行的任务方法被置于std::queue<Job> jobs
。为什么只有指向operator()
的{{1}}的指针保存std::packaged_task
中作为方法参数给出的Function
的引用?我希望直接存储std::queue
以保存对正在创建的实例的引用...?
无论如何,源代码片段来自ThreadPool实现,可以在https://github.com/dabbertorres/ThreadPool找到并且似乎完全正常。所以我认为这是正确的,但遗憾的是我并不完全清楚...如果有人能解释这些东西是如何工作的话,我会很高兴...
非常感谢愿意提供帮助的任何人。干杯马丁
答案 0 :(得分:3)
正如您在add(...)方法体中看到的那样,实例 std :: packaged_task - task是局部变量,其范围以 方法执行结束。
是的,它是std::shared_ptr<PackedTask>
的局部变量。当它超出范围时,它将引用计数减1.如果新引用计数为0,它将删除它指向的对象。幸运的是,jobs
拥有该共享指针的副本,因此指向对象保持活动状态。
std :: future类型的返回值ret由副本返回。
不完全是。 移动而不是通过复制返回ret
的可能性更大。
任务超出范围,所以我期待连接的std :: future 被返回的实例变得无效,我的理解是否正确?
同样,task
是一个共享指针。 jobs
队列使其保持活动状态,并且可能ret
保存该共享指针的另一个副本(以实际提取task
的结果)。所以只要任务在队列中并且某人将未来留给该结果,任何事情都不会变得无效。
我希望直接存储std :: packaged_task以便 保持对正在创建的实例的引用...?
是的,它可以直接存储std::packaged_task
。我的猜测是这个图书馆的作者并不想搞乱不可操作/不可移动的仿函数。如果std::bind
的结果不可复制且不可移动,则无法将std::packaged_task
真正移至队列中。使用共享指针解决了这个问题,因为你不复制/移动packaged_task本身,只有指针。但是,您可以将任务对象直接构建到队列中,但是在保持锁定下执行它并不是一个好习惯。
我确实同意,将task
移动到lambda中比复制它更有效。
答案 1 :(得分:1)
所以一旦方法执行完成,任务超出范围,所以我希望连接的std :: future实例返回无效,我的理解是否正确?
task
是一个std::shared_ptr
,被复制到传递给jobs
的闭包中 - 只要作业存在,它就会保持活着。
答案 2 :(得分:0)
所以一旦方法执行完成,任务超出范围,所以我希望连接的std :: future实例返回无效,我的理解是否正确?
没有
future
是共享状态的句柄。这种状态由承诺和未来共享。
将其视为将一种特殊的shared_ptr
封装到管理承诺/未来关系状态的(不透明)对象中。