C++11 是否保证释放围栏和使用操作之间的内存顺序

Does C++11 guarantee memory ordering between a release fence and a consume operation?

本文关键字:操作 之间 顺序 内存 是否 释放 C++11      更新时间:2023-10-16

请考虑以下代码:

struct payload
{
    std::atomic< int > value;
};
std::atomic< payload* > pointer( nullptr );
void thread_a()
{
    payload* p = new payload();
    p->value.store( 10, std::memory_order_relaxed );
    std::atomic_thread_fence( std::memory_order_release );
    pointer.store( p, std::memory_order_relaxed );
}
void thread_b()
{
    payload* p = pointer.load( std::memory_order_consume );
    if ( p )
    {
        printf( "%dn", p->value.load( std::memory_order_relaxed ) );
    }
}

C++是否保证线程 a 中的栅栏与线程 b 中的消耗操作的交互?

我知道在此示例中,我可以用商店发布替换围栏 + 原子存储并让它工作。 但我的问题是关于使用围栏的这种特殊情况。

阅读标准文本,我可以找到有关释放围栏与获取围栏以及释放围

栏与获取操作交互的子句,但没有关于释放围栏和使用操作交互的任何子句。

我认为,用获取替换消耗将使代码符合标准。 但据我了解处理器实现的内存排序约束,我应该只真正要求线程 b 中较弱的"消耗"排序,因为内存屏障强制线程 a 中的所有存储在存储指向指针之前可见,并且读取有效负载取决于从指针读取。

标准是否一致?

你的代码有效。

我知道在此示例中,我可以用商店发布替换围栏 + 原子存储并让它工作。但我的问题是关于使用围栏的这种特殊情况。

具有松弛原子操作的围栏比相应的原子操作更强。 例如(来自 http://en.cppreference.com/w/cpp/atomic/atomic_thread_fence,注释):

原子存储释放操作阻止所有先前的写入通过存储发布,而具有memory_order_release排序的atomic_thread_fence阻止所有先前的写入通过所有后续存储。

尽管这显然是意图,但指定栅栏和原子操作交互的方式意味着官方仅支持列出的组合。(这种规范风格不仅冗长,难以阅读,更难转化为有效的直觉,很容易使不完整。

我在标准支持中看不到任何将消费操作与发布屏障配对的内容,即使正常实现不可能不支持,除非在全局程序优化期间通过特殊努力来检测该特定用例并故意破坏它