首页 > 解决方案 > 在 C++11 中获取/释放 VS 顺序一致性?

问题描述

#include <thread>
#include <atomic>
#include <cassert>

std::atomic<bool> x = {false};
std::atomic<bool> y = {false};
std::atomic<int> z = {0};

void write_x()
{
    x.store(true, std::memory_order_release);
}

void write_y()
{
    y.store(true, std::memory_order_release);
}

void read_x_then_y()
{
    while (!x.load(std::memory_order_acquire))
        ;
    if (y.load(std::memory_order_acquire)) {
        ++z;
    }
}

void read_y_then_x()
{
    while (!y.load(std::memory_order_acquire))
        ;
    if (x.load(std::memory_order_acquire)) {
        ++z;
    }
}

int main()
{
    std::thread a(write_x);
    std::thread b(write_y);
    std::thread c(read_x_then_y);
    std::thread d(read_y_then_x);
    a.join(); b.join(); c.join(); d.join();
    assert(z.load() != 0);
}

如果我在cppreference 的最后一个示例中将 seq_cst 替换为获取/释放,assert(z.load() != 0)会失败吗?

标签: c++atomicmemory-barriersmemory-modelstdatomic

解决方案


是的,如果您使用/订购,则可能z.load() == 0在您的代码中。独立写入和之间没有发生之前的关系。cppreference 使用该示例专门用于说明获取/释放不足的情况并非巧合。acquirereleasexy

这有时被称为 IRIW(独立读取独立写入),并且在某些硬件排序模型中往往被掩盖。特别是,仅根据可能的加载加载、加载存储、存储存储等定义的内存模型,重新排序并没有真正说明 IRIW。在 x86 内存模型中,IRIW 重新排序是不允许的,因为有一个子句解释了存储具有总顺序并且所有处理器都以相同的顺序查看存储。

我不知道在使用获取和释放所需的障碍和/或指令时,是否有任何常用的 CPU 承认 IRIW 重新排序,但如果有人这样做,我不会感到惊讶。


推荐阅读