C ++中是否存在任何隐式内存障碍

时间:2019-05-01 07:19:00

标签: c++ c++11 atomic memory-model

在下面的代码中,正在使用必要的原子来保证所有平台上的无种族语义,或者是否使用了promise.set_value / future.wait暗示某种隐式的内存屏障,它将使我能够依靠标记写对外线程已经可见了?

std::atomic_bool flag{false}; // <- does this need to be atomic?
runInThreadPoolBlocking([&]() {
    // do something
    flag.store(true);
});
if (flag.load()) // do something


// simplified runInThreadPoolBlocking implementation
template <typename Callable>
void runInThreadPoolBlocking(Callable func)
{
    std::promise<void> prom;
    auto fut = prom.get_future();

    enqueueToThreadPool([&]() {
        func();
        prom.set_value();
    });

    fut.get();
}

通常,对于thread.join()或Future之类的标准,该标准是否有任何“隐式”内存屏障?

2 个答案:

答案 0 :(得分:3)

thread.join()promise.set_value() / future.wait()保证暗示内存障碍。

如果您不希望编译器用其他代码对布尔检查或赋值重新排序,则必须使用atomic_bool。但是在那种特殊情况下,您不能使用原子bool。如果您未在其他任何地方使用flag,则可以保证truefut.get(),因为分配和检查位于同步点的相反侧({{1 }})(强制编译器加载实际的flag值),并保证函数runInThreadPoolBlocking()仅在执行lambda之后才能完成。

cplusplus.comfuture::get()的报价,例如:

  

数据竞赛

     
     

修改了将来的对象。共享状态作为   原子操作(不引起数据争用)。

promise::set_value()也是如此。除了其他东西

  

...原子操作(不引起数据争用)...

意味着没有一个冲突的评估发生在另一个评估之前(严格的内存排序)。

所有std::多线程同步原语和工具也是如此,您希望其中一些操作仅在同步点之前或之后发生(例如std::mutex::lock()unlock(),{{1} }等。

请注意,线程对象本身的任何操作都不会与thread::join()同步(不同于它所代表的线程内的操作)。

答案 1 :(得分:-2)

std::atomic_bool flag{false}; // <- does this need to be atomic?

通话:

prom.get_future()

返回一个std::future<void>对象。

为了将来,参考文献指出:

  

类模板std :: future提供了一种机制来访问   异步操作的结果:

     

异步操作(通过std :: async,std :: packaged_task或std :: promise创建)可以提供std :: future对象   异步操作的创建者。

     

然后,异步操作的创建者可以使用多种方法来查询,等待或从中提取值。   std :: future。 如果异步操作具有   尚未提供值。

     

当异步操作准备好将结果发送给创建者时,它可以通过修改共享状态来实现(例如   std :: promise :: set_value)链接到创建者的std :: future。

     

请注意,std :: future引用了未与任何其他异步返回对象共享的共享状态(相对于   std :: shared_future)。

您无需在此处存储“返回”值,因此该点有点无语,并且由于没有其他担保人(并且整个想法是线程可能仍在并行运行!),因此需要保留布尔值如果共享,则为原子!