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

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

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/

相关文章:

c++ - 我可以使用 std::pair,但重命名 .first 和 .second 成员名称吗?

c++ - XE2 - Indy TCPServer : what is the best way to write and read a listview?

c++ - 为类的特征特化实现错误消息

c++ - 签署零 linux 与 windows

data-structures - 以原子方式从 Redis 数据结构中弹出多个值?

ruby-on-rails - 使用 Rails 和 Postgres 获取原子计数器(增量)的值

r - 如何访问原子向量属性?

c++ - 获取当前类的 typedef

mysql - 对于可变数量的组合,最佳的表结构是什么?

ios - ARC 的多线程自动释放问题?