32位读取的_compiler_barrier()的目的



我一直在使用64位项目分配给VS2017上的atomic_long类型时介入涉及的函数调用。我特别想看看将atomic_long复制到非原子变量时会发生什么,如果周围有任何锁定。

atomic_long ll = 10;
long t2 = ll;

最终以此调用结束(我已删除了一些被 ifdef ed的代码(

inline _Uint4_t _Load_seq_cst_4(volatile _Uint4_t *_Tgt)
    {   /* load from *_Tgt atomically with
            sequentially consistent memory order */
    _Uint4_t _Value;
    _Value = *_Tgt;
    _Compiler_barrier();
    return (_Value);
    }

现在,我已经从MSDN读到,对32位值的平整读取将是原子:

简单的读取和写入正确对齐的32位变量是 原子操作。

...这说明了为什么只有Interlocked函数仅用于阅读;只有用于更改/比较的人。我想知道的是_Compiler_barrier()位在做什么。这是

#define d
__MACHINE(void _ReadWriteBarrier(void))

...我又在MSDN上发现了这个

限制了可以重新排序内存访问的编译器优化 在通话的点上。

但我没有得到这个,因为除了return调用之外,没有其他内存访问;当然,编译器不会在下面移动作业吗?

有人可以澄清这个障碍的目的吗?

_Load_seq_cst_4inline函数。编译器屏障在那里可以阻止重新排序使用以后的代码在调用函数中,该嵌入到

中。

例如,考虑阅读seqlock。(与此实际实施相比过于简单(。

#include <atomic>
atomic<unsigned> sequence;
atomic_long  value;
long seqlock_try_read() {
    // this would normally be the body of a retry-loop;
    unsigned seq1 = sequence;
    long tmpval = value;
    unsigned seq2 = sequence;
    if (seq1 == seq2 && (seq1 & 1 == 0)
        return tmpval;
    else
        // writer was modifying it, we should retry the loop
}

如果我们没有阻止编译时间重新排序,则编译器可以将sequence的两种读取合并到一个访问中,例如也许像这样

    long tmpval = value;
    unsigned seq1 = sequence;
    unsigned seq2 = sequence;

这将打败锁定机制(在修改数据之前,作者一次将sequence递增,然后在完成数据后再次增加(。读者完全是无锁的,但这不是"无锁"算法

内的屏障每个 load功能在内线后用其他事物重新排序。

(C 11内存模型非常弱,但是X86存储器模型很强,仅允许保存重新排序。通过以后的负载/商店阻止编译时间重新排序足以为您提供获得/顺序抗性负载在运行时。x86:这里需要内存屏障吗?(


btw,一个更好的示例可能是某些非atomic变量在atomic标志中看到某个值后读取/写入的东西。MSVC可能已经避免重新排序或合并原子访问,在SEQLOCK中,所保护数据也必须为atomic

为什么编译器不合并冗余std :: Atomic写入?

最新更新