锁定时的C - volatile限定符

时间:2017-05-22 17:27:46

标签: c concurrency locking volatile nonatomic

我是否需要仅在锁定时访问的变量的volatile限定符?在此代码中,可以从n中删除volatile限定符,可能会在concurrent_foo同时执行时更改行为。

#ifndef __GNUC__
#error __sync_lock builtins are only available with GCC
#endif

volatile int n = 0;
static volatile int lock = 0;

void concurrent_foo () {
    while (__sync_lock_test_and_set (&lock, 1));
    // Non-atomic operation, protected by spinlock above.
    int x = n % 2 + 1;
    n = n + x;
    __sync_lock_release (&lock);
}

我知道volatile限定符指示编译器不要优化对变量的内存访问。我也明白__sync_lock内置问题是一个(完整?)内存屏障,内存访问不应该交叉。但是,在此示例代码中,获取n,将其缓存在寄存器中,计算新值,然后将其写回n将是安全的。

使用-O3使用GCC到i686源代码进行编译,发现有两次内存提取,无论如何:

concurrent_foo:
        movl        $1, %edx
.L2:
        movl        %edx, %eax
        xchgl        lock, %eax
        testl        %eax, %eax
        jne        .L2
        movl        n, %eax
        movl        n, %edx
        movl        %eax, %ecx
        shrl        $31, %ecx
        addl        %ecx, %eax
        andl        $1, %eax
        subl        %ecx, %eax
        leal        1(%edx,%eax), %eax
        movl        %eax, n
        movl        $0, lock
        ret

如果没有volatile限定符,我会得到微妙的不同代码,其中n只被提取一次:

concurrent_foo:
        movl        $1, %edx
.L2:
        movl        %edx, %eax
        xchgl        lock, %eax
        testl        %eax, %eax
        jne        .L2
        movl        n, %edx
        movl        %edx, %ecx
        shrl        $31, %ecx
        leal        (%edx,%ecx), %eax
        andl        $1, %eax
        subl        %ecx, %eax
        leal        1(%edx,%eax), %eax
        movl        %eax, n
        movl        $0, lock
        ret

在这两种情况下,在保持锁定时会发生对n的存储器访问,因此应该是“正确的”。但是,我不确定我是否真的得到了保证。 volatile限定符阻止了我想要的性能优化,并且不会影响操作的结果(任何时候n都不会是偶数)。

0 个答案:

没有答案
相关问题