C++ 编译器重新排序和加载操作

C++ 编译器重新排序和加载操作,c++,atomic,C++,Atomic,我开始了无锁编程,在基本的东西上遇到了一些困难。我发现了以下例子: #define COMPILER_BARRIER() asm volatile("" ::: "memory") int Value; int IsPublished = 0; void sendValue(int x) { Value = x; COMPILER_BARRIER(); // prevent reordering of stores IsPublished = 1;

我开始了无锁编程,在基本的东西上遇到了一些困难。我发现了以下例子:

#define COMPILER_BARRIER() asm volatile("" ::: "memory")

int Value;
int IsPublished = 0;

void sendValue(int x)
{
    Value = x;
    COMPILER_BARRIER();          // prevent reordering of stores
    IsPublished = 1;
}

int tryRecvValue()
{
    if (IsPublished)
    {
        COMPILER_BARRIER();      // prevent reordering of loads
        return Value;
    }
    return -1;  // or some other value to mean not yet received
}
编译器可以在
tryRecvValue
函数中执行什么样的重新排序?

答案 如果没有内联asm*,编译器可以先从
value
加载值,然后从
IsPublished
加载值,然后执行检查并返回

如果不确定编译器在做什么,请始终检查程序集输出。无锁编程技术尤其如此

更多信息 注:内联ASM不是C++标准的必要部分,而是由所有主要编译器实现的。仅在第7.4节中提及:

asm声明是有条件支持的;它的含义是实现定义的。[注:通常情况下 用于通过实现将信息传递给汇编程序。-结束说明]

一般来说,编译器无法对内联程序集的读写进行重新排序,因为编译器无法对程序集的功能进行假设

上面使用的
COMPILER\u BARRIER()
不会充当任何类型的读/写屏障,它只是有一个副作用,即不允许对语句周围的汇编指令重新排序

假设上面的代码是从不同的线程调用的,它将只在x86上按原样工作,因为体系结构保证写入不会(明显地)被cpu重新排序。(参考:第3A卷中的8.2.3.2)


对于其他具有宽松内存模型的体系结构(如PowerPc和ARM),您需要硬件屏障来阻止这些类型的重新排序。要获得一个好的分类,请查看。

以防万一您错过了它:C++11这些东西,因此不需要使用asm(理论上)
COMPILER\u BARRIER()
将充当编译器的读写屏障。需要明确的是:它对CPU无序执行没有影响。