c – 用GCC进行原子64位写入

前端之家收集整理的这篇文章主要介绍了c – 用GCC进行原子64位写入前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我已经陷入了一个混乱的混乱的多线程编程,并希望有人可以来和我的一些理解.

在做了相当多的阅读之后,我已经明白,我应该能够在64位系统1上设置64位int原子值的值.

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

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;
    }
}

我设一个= 1844674407370955161;和b = 1144644202170355111 ;.我运行这个程序,没有输出警告我,blah不是a或b.

好的,看起来可能是一个原子写…但是,我改变了第一个线程直接设置a和b,像这样:

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.您可以尝试强制使用一个临时变量使用寄存器,但是这可能无法正常工作.

参考文献:

> mov
> movq

猜你在找的C&C++相关文章