简体   繁体   English

在使用 memory_order_relaxed 编译一个 std::atomic 加载时,编译器能否发明多个加载?

[英]Can a compiler invent multiple loads when compiling one std::atomic load using memory_order_relaxed?

Taking the following piece of code采取以下代码

struct SharedMemory
{
  std::atomic<float> value;

  bool shouldReturnTrue()
  {
    float tmp = value.load(std::memory_order_relaxed);
    float a = tmp;
    float b = tmp;
    return a == b;
  }
};

Is it legal for the compiler to optimize it as follow and so break the thread safety?编译器如下优化它并破坏线程安全是否合法?

struct SharedMemory
{
  std::atomic<float> value;

  bool shouldReturnTrue()
  {
    float a = value.load(std::memory_order_relaxed);
    float b = value.load(std::memory_order_relaxed);
    return a == b;
  }
};

If so, should I force it to not optimize tmp using volatile keyword as follow?如果是这样,我是否应该强制它不使用volatile关键字优化tmp ,如下所示?

struct SharedMemory
{
  std::atomic<float> value;

  bool shouldReturnTrue()
  {
    volatile float tmp = value.load(std::memory_order_relaxed);
    float a = tmp;
    float b = tmp;
    return a == b;
  }
};

No, that wouldn't be a legal optimization.不,那不是合法的优化。 As you say, it could return false for cases other than tmp being NaN, if there was a writer.正如您所说,如果有作者,它可能会在tmp为 NaN 以外的情况下返回 false。 Therefore it wouldn't be valid per the as-if rule, because the C++ abstract machine does always return !isnan(tmp) .因此,根据 as-if 规则,它是无效的,因为 C++ 抽象机确实总是返回!isnan(tmp)

(If you'd picked a type like int where self == self was always true, it would be easier to talk about!) (如果你选择了一个像int这样的类型,其中self == self总是为真,那么谈论它会更容易!)

The transformation you ask about is only legal for non-atomic variables, precisely because the value can be assumed not to be changing.您询问的转换仅对非原子变量合法,正是因为可以假定该值不会改变。 If it is, that would be data-race undefined behaviour, and compilers are allowed to assume no UB.如果是,那将是数据竞争未定义行为,并且允许编译器假设没有 UB。 Thus they can invent another non-atomic non-volatile load if that's more convenient for register allocation.因此,如果寄存器分配更方便,他们可以发明另一种非原子非易失性负载。

But an atomic variable does have to be assumed to change value between any two reads (in this way similar to volatile in terms of what compilers have to assume about it), because that is well-defined behaviour that compilers have to respect.但是必须假定atomic变量在任意两次读取之间更改值(在这种方式下,就编译器必须假设的内容而言,类似于volatile ),因为这编译器必须遵守的明确定义的行为。

So the compiler will never invent reads of atomic<> objects .所以编译器永远不会发明atomic<> objects 的读取 (That linked article is about Linux kernel code, where they use volatile for hand-rolled atomics on compilers that are known to work the way they want , for the same reasons we use std::atomic<> in modern C++.) (那篇链接的文章是关于 Linux kernel 代码的,他们在编译器上使用volatile来手动滚动原子,这些编译器以他们想要的方式工作,原因与我们在现代 C++ 中使用std::atomic<>的原因相同。)

memory_order_relaxed means that the ordering wrt. memory_order_relaxed意味着订购wrt。 surrounding memory accesses is relaxed, not the atomicity guarantees.周围的 memory 访问是宽松的,不是原子性保证。 In this respect, relaxed isn't different from acquire or seq_cst .在这方面, relaxedacquireseq_cst没有什么不同。 I guess you had some misconception that relaxed might be relevant here, but it isn't.我猜你有一些误解,认为relaxed可能与此相关,但事实并非如此。


You're right that assigning the load result to volatile float tmp would make it less likely for a compiler to want to invent loads, but if that was a real problem (it isn't), a better way would be to use volatile atomic<float> value;你是对的,将加载结果分配给volatile float tmp会使编译器不太可能想要发明加载,但如果这是一个真正的问题(不是),更好的方法是使用volatile atomic<float> value; . . Again, this is not necessary .同样,这不是必需的。 Especially now, since compilers currently don't optimize atomics at all ( Why don't compilers merge redundant std::atomic writes? ) but even in future with compilers that only give you the bare minimum ISO C++ standard and do optimize atomics by eg coalescing redundant back-to-back reads into one, they won't be allowed to do the other thing and invent extra writes, or invent extra reads and assume the value is the same.特别是现在,因为编译器目前根本不优化原子( 为什么编译器不合并冗余的 std::atomic 写入? )但即使在未来编译器只给你最低限度的 ISO C++ 标准并通过例如优化原子将冗余的背靠背读取合并为一个,他们不允许做另一件事并发明额外的写入,或发明额外的读取并假设值相同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 std :: memory_order_relaxed相对于同一原子变量的原子性 - std::memory_order_relaxed atomicity with respect to the same atomic variable 在唯一写入该变量的线程中,使用memory_order_relaxed加载原子变量是否安全? - Is it safe to use memory_order_relaxed to load an atomic variable, when in the only thread that writes to that variable? memory_order_relaxed 和 Atomic RMW 操作 - memory_order_relaxed and Atomic RMW operations std :: atomic_bool用于取消标志:是std :: memory_order_relaxed正确的内存顺序? - std::atomic_bool for cancellation flag: is std::memory_order_relaxed the correct memory order? 的std ::原子 <int> memory_order_relaxed多线程程序中的VS volatile sig_atomic_t - std::atomic<int> memory_order_relaxed VS volatile sig_atomic_t in a multithreaded program std :: memory_order_relaxed和初始化 - std::memory_order_relaxed and initialization memory_order_relaxed 如何在智能指针中增加原子引用计数? - How can memory_order_relaxed work for incrementing atomic reference counts in smart pointers? 是防止部分读取原子存储所必需的“memory_order_relaxed” - is `memory_order_relaxed` necessary to prevent partial reads of atomic stores 对原子类感到困惑:memory_order_relaxed - confused about atomic class: memory_order_relaxed "fetch_sub 和 memory_order_relaxed 用于原子引用计数?" - fetch_sub with memory_order_relaxed for atomic reference counting?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM