标准是否保证在移动std :: packaged_task后安全使用std :: future?

时间:2019-06-27 14:22:07

标签: c++ multithreading c++11 thread-safety

假设我们有以下代码:

#include <iostream>
#include <future>

int main() {
    auto packagedTask = std::packaged_task<int()>([] {
        std::cout << "hello!\n";
        return 10;
        });

    auto packagedTaskFuture = packagedTask.get_future();
    auto packagedTaskPtr = std::make_shared<decltype(packagedTask)>(std::move(packagedTask));

    auto v1 = packagedTaskFuture.valid(); // is valid
    auto v2 = packagedTaskFuture.wait_for(std::chrono::seconds(0)); // timeout state
    (*packagedTaskPtr)(); // execute task
    auto v3 = packagedTaskFuture.wait_for(std::chrono::seconds(1)); // ready state
    auto v4 = packagedTaskFuture.get(); // 10

    return 0;
}

它在我的Visual Studio环境下运行完美,如您所见,我在将std::future移至新创建的std::packaged_task之前就检索了std::shared_ptr。我已经研究了关于std::packaged_task的C ++标准,因此§30.6.9.1packaged_task(packaged_task&& rhs) noexcept第6页:

  

作用:构造一个新的packaged_task对象,并将rhs共享状态的所有权转让给* this,使rhs没有共享状态。将存储的任务从rhs移到* this。

,第30.6.9页第2页说:

  

当调用packaged_task对象时,将调用其存储的任务,并将结果(无论正常还是例外)存储在共享状态下。任何具有共享状态的期货都将能够访问存储的结果。

基于此信息,我有两个问题:

1)我说对了std::packaged_task之后将std::future链接到相同的std::move吗?

2)在其他线程中使用我的std::shared_ptr并在那里执行任务,并从当前线程中检查std::future是否安全?

1 个答案:

答案 0 :(得分:2)

因此,标准讨论的是(隐藏的)共享状态。共享状态在基于std::move的副本上移动。

应该将对象(打包的任务,将来的对象)视为具有对该共享状态的引用的各种智能指针。

存在竞争条件可能是由于该共享状态在多个线程中进行交互而引起的。唯一可能发生的竞争条件是,如果您正在多个线程中与同一 object 进行交互,并且在至少一个线程中调用了非{const方法。

C ++并发原语中的“共享状态”是概念性的,不能保证甚至是一个对象。它没有方法。

是的,是的。