首页 > 解决方案 > C++ 中是否存在任何隐式内存屏障

问题描述

在下面的代码中,是使用必要的原子来保证所有平台上的无竞争语义,还是使用 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() 或期货之类的东西,标准是否保证了任何“隐式”内存屏障?

标签: c++c++11atomicmemory-model

解决方案


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

atomic_bool如果您不希望编译器使用其他代码重新排序布尔检查或赋值,则使用是必要的。但在那种特殊情况下,您可以使用 not atomic bool。如果您不在任何其他地方使用它,那flag将保证在检查时进行,因为分配和检查位于同步点 ( ) 的相对侧(强制编译器加载实际值)和函数保证只有在 lambda 执行后才能完成。truefut.get()flagrunInThreadPoolBlocking()

引用cplusplus.com的内容future::get(),例如:

数据竞赛


未来对象被修改。共享状态作为原子操作访问(不会导致数据竞争)。

对于promise::set_value(). 除了其他东西

... 原子操作(不会导致数据争用) ...

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

所有std::多线程同步原语和工具也是如此,您希望某些操作仅在同步点之前或之后发生(如std::mutex::lock()or unlock()thread::join()等)。

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


推荐阅读