gpt4 book ai didi

c++ - C++内存顺序的理解,我错了吗?

转载 作者:行者123 更新时间:2023-12-02 03:30:24 30 4
gpt4 key购买 nike

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

std::atomic<bool> x = false, y = false, go = false;
int v = 0;

// t1
void write_xy() {
while (!go) {
std::this_thread::yield();
}

v = 1; // 1
x.store(true, std::memory_order_relaxed); // 2
y.store(true, std::memory_order_relaxed); // 3
}

// t2
void read_yx() {
while (!go) {
std::this_thread::yield();
}

while (!y.load(std::memory_order_relaxed))
;

assert(1 == x.load(std::memory_order_relaxed)); // 4
assert(1 == v); // 5
}

int main() {
for (;;) {
x = false;
y = false;
v = 0;

go = false;
std::thread t1(write_xy);
std::thread t2(read_yx);
go = true; // start
t1.join();
t2.join();
}
}

作为一个C++并发编程的初学者,根据我对memory_order_relaxed的理解,上面代码中t1线程中的三个语句的执行顺序是看不出来的到t2。从t2的角度来看,t1中的三个语句可能具有3、2、1的顺序,因此4和5处的断言可能会被触发。

经过多次尝试,assert从未触发,所以我编写了一个无限循环重复上述过程,并且assert仍然没有触发。后来怀疑t1t2开始执行之前就结束了,于是引入了go变量在两个线程的开始处等待,以确保两个线程都尽快开始执行,但仍然没有触发 assert

我在具有 Centos8 和 4 个 CPU 的虚拟机上进行测试。我的CPU是i5-7500。

最佳答案

仅仅语言允许某些事情发生并不意味着您能够在给定的情况下重现它。

现在让我们忽略 v 上的数据争用(即使这意味着您的程序具有未定义的行为)。

您正在编译 x86 的代码,它对内置的内存排序有非常强大的保证。例如,当您使用 std::memory_order_release 执行存储时,您将获得完全相同的汇编代码:

https://godbolt.org/z/pZaFDC

    mov     DWORD PTR v[rip], 1
mov BYTE PTR x[rip], 1
mov BYTE PTR y[rip], 1

因此,当 y 时,这段代码(针对您的 CPU 编译的)保证对所有其他线程都可见 v == 1x == 1 == 1 。您的 C++ 程序没有这种保证,但这个机器代码有。

类似地,使用 std::memory_order_acquire 进行加载也没有效果(只有断言消息的文本发生变化):

https://godbolt.org/z/e2-uNA

    movzx   eax, BYTE PTR y[rip]
[...]
movzx eax, BYTE PTR x[rip]
[...]
cmp DWORD PTR v[rip], 1

同样,该平台已经提供了必要的保证。其他平台(例如 ARM)提供的保证较少,您会在编译的二进制文件中看到差异:

https://godbolt.org/z/Ru4YdD

这里,同步被添加到所有存储和读取中:

    bl      __sync_synchronize

上面的 x86 代码也是为什么 v 上的数据争用此时不起作用的原因。 但是,依赖于此是一个糟糕的主意,因为编译器完全有权利这样做,例如将 assert(v == 1); 移到 while (!y.load(std::memory_order_relaxed)) 之前。只是目前还没有这样做。

获取断言的另一种方法是编译器重新排序加载和存储。允许这样做(而上面的释放获取排序则不允许这样做),但事实并非如此,大概是因为这样做没有意义。您也许可以通过更改周围的代码来诱使它这样做,但我无法想出一种方法来做到这一点。

关于c++ - C++内存顺序的理解,我错了吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58953985/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com