我正在开始无锁编程,我在基本的东西上遇到了一些困难。我找到了以下示例:
#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
加载值,然后执行检查并返回。
如果您不确定编译器正在做什么,请始终检查程序集输出。对于无锁编程技术尤其如此。
更多信息
* 注意:内联汇编不是 C++ 标准的必需部分,但所有主要编译器都已实现。仅在7.4节中提到:
The asm declaration is conditionally-supported; its meaning is implementation-defined. [ Note: Typically it is used to pass information through the implementation to an assembler. — end note ]
一般来说,编译器无法围绕内联汇编重新排序读取和写入,因为编译器无法假设汇编的作用。
上面 COMPILER_BARRIER()
的使用不会充当任何类型的读/写屏障,它只是具有不允许在语句周围重新排序汇编指令的副作用。
假设上面的代码是从不同的线程调用的,它只能在 x86 上按原样工作,因为架构保证写操作永远不会(可观察到)被 cpu 重新排序。 (引用:Intel Manuals 卷 3A 中的 8.2.3.2)
要在具有宽松内存模型的其他架构(如 PowerPc 和 ARM)上使用,您需要硬件屏障来防止这些类型的重新排序。如需详细了解,请查看 Jeff Preshing's articles .
关于c++ - 编译器重新排序和加载操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27432621/