gpt4 book ai didi

c++ - 使用 GCC 进行原子 64 位写入

转载 作者:IT老高 更新时间:2023-10-28 23:10:55 24 4
gpt4 key购买 nike

我在多线程编程方面陷入了困惑,希望有人能来给我一些理解。

经过大量阅读后,我了解到我应该能够在 64 位系统上以原子方式设置 64 位 int 的值1

虽然我发现很多阅读困难,所以我想我会尝试做一个测试来验证这一点。所以我用一个线程编写了一个简单的程序,它将一个变量设置为两个值之一:

bool switcher = false;

while(true)
{
if (switcher)
foo = a;
else
foo = b;
switcher = !switcher;
}

另一个线程会检查 foo 的值:

while (true)
{
__uint64_t blah = foo;
if ((blah != a) && (blah != b))
{
cout << "Not atomic! " << blah << endl;
}
}

我设置了 a = 1844674407370955161;b = 1144644202170355111;。我运行这个程序并没有得到任何输出警告我 blah 不是 ab

太好了,看起来可能是原子写入...但是,我将第一个线程更改为直接设置 ab,如下所示:

bool switcher = false;

while(true)
{
if (switcher)
foo = 1844674407370955161;
else
foo = 1144644202170355111;
switcher = !switcher;
}

我重新运行,突然:

Not atomic! 1144644203261303193
Not atomic! 1844674406280007079
Not atomic! 1144644203261303193
Not atomic! 1844674406280007079

发生了什么变化?无论哪种方式,我都在为 foo 分配一个大数字 - 编译器是否以不同的方式处理一个常数,还是我误解了一切?

谢谢!


1: Intel CPU documentation, section 8.1, Guaranteed Atomic Operations

2: GCC Development list discussing that GCC doesn't guarantee it in the documentation, but the kernel and other programs rely on it

最佳答案

反汇编循环,我用 gcc 得到以下代码:

.globl _switcher
_switcher:
LFB2:
pushq %rbp
LCFI0:
movq %rsp, %rbp
LCFI1:
movl $0, -4(%rbp)
L2:
cmpl $0, -4(%rbp)
je L3
movq _foo@GOTPCREL(%rip), %rax
movl $-1717986919, (%rax)
movl $429496729, 4(%rax)
jmp L5
L3:
movq _foo@GOTPCREL(%rip), %rax
movl $1486032295, (%rax)
movl $266508246, 4(%rax)
L5:
cmpl $0, -4(%rbp)
sete %al
movzbl %al, %eax
movl %eax, -4(%rbp)
jmp L2
LFE2:

所以看起来 gcc 确实使用了具有 32 位立即值的 32 位 movl 指令。有一条指令 movq 可以将 64 位寄存器移动到内存(或将内存移动到 64 位寄存器),但它似乎无法设置将立即值移动到内存地址,因此编译器被迫要么使用临时寄存器,然后将值移动到内存中,要么使用到 movl。您可以尝试通过使用临时变量来强制它使用寄存器,但这可能不起作用。

引用资料:

关于c++ - 使用 GCC 进行原子 64 位写入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5258627/

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