6

我正在分析以下代码片段,并试图详细了解它:

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是局部变量,其作用域以方法执行结束而结束。type的返回值retstd::futurecopy返回的。的值ret是由task(本地的)给出的。因此,一旦方法执行完成,task就会超出范围,所以我希望返回的连接的 std::future 实例变得无效,我的理解是否正确?

在方法的执行过程中,要在线程中执行的任务方法被放置到std::queue<Job> jobs. 为什么只有指向 which 的指针operator()持有std::packaged_taskFunction给定方法参数的引用std::queue?我希望直接存储std::packaged_task以保存对正在创建的实例的引用......?

无论如何,源代码片段来自 ThreadPool 实现,可以在这里找到https://github.com/dabbertorres/ThreadPool并且似乎完全可以工作。所以我认为这是正确的,但不幸的是我并不完全清楚......如果有人能解释这些东西是如何工作的,我会很高兴......

非常感谢任何愿意提供帮助的人。干杯马丁

4

3 回答 3

4

正如您在 add(...) 方法体中看到的那样,std::packaged_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 比复制它更有效。

于 2017-10-10T08:44:58.093 回答
2

因此,一旦方法执行完成,任务就会超出范围,所以我希望返回的连接的 std::future 实例变得无效,我的理解是否正确?

task是一个std::shared_ptr被复制到传递给的闭包中jobs- 只要工作存在,它就会一直保持活动状态。

于 2017-10-10T08:35:47.597 回答
1

因此,一旦方法执行完成,任务就会超出范围,所以我希望返回的连接的 std::future 实例变得无效,我的理解是否正确?

不。

future是共享状态的句柄。这个状态是由promise和future共享的。

可以将其视为对(不透明)对象封装一种特殊的类型,shared_ptr该对象管理承诺/未来关系的状态。

于 2017-10-10T08:44:24.723 回答