对原子类感到困惑:memory_order_relaxed [英] confused about atomic class: memory_order_relaxed

查看:71
本文介绍了对原子类感到困惑:memory_order_relaxed的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究此网站: https://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync ,对于理解有关原子类的主题非常有帮助.

I am studying this site: https://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync, which is very helpful to understand the topic about atomic class.

但是关于放松模式的这个例子很难理解:

But this example about relaxed mode is hard to understand:

    /*Thread 1:*/

    y.store (20, memory_order_relaxed)
    x.store (10, memory_order_relaxed)
    /*Thread 2*/
 if (x.load (memory_order_relaxed) == 10)
      {
        assert (y.load(memory_order_relaxed) == 20) /* assert A */
        y.store (10, memory_order_relaxed)
      }
 /*Thread 3*/
     if (y.load (memory_order_relaxed) == 10)
        assert (x.load(memory_order_relaxed) == 10) /* assert B */

对我来说,B应该永远不会失败,因为x必须为10并且y = 10(因为线程2对此有所限制).

To me assert B should never fail, since x must be 10 and y=10 because of thread 2 has conditioned on this.

但是网站说,这个例子中的任何一个断言实际上都可能失败.

But the website says either assert in this example can actually FAIL.

推荐答案

我发现了解原子可能会导致原子的原因要容易得多,所以这里有一些背景知识.知道这些概念并没有在C ++语言本身中陈述过,但这是事物按其原样运行的一些可能原因.

I find it much easier to understand atomics with some knowledge of what might be causing them, so here's some background knowledge. Know that these concepts are in no way stated in the C++ language itself, but is some of the possible reasons why things are the way they are.

编译器通常在优化时会选择重构程序,只要它对单个线程程序的作用相同.这是通过使用原子来避免的,原子将告诉编译器(除其他事项外)变量随时可能更改,并且其值可能在其他位置读取.

Compilers, often when optimizing, will choose to refactor the program as long as its effects are the same on a single threaded program. This is circumvented with the use of atomics, which will tell the compiler (among other things) that the variable might change at any moment, and that its value might be read elsewhere.

形式上,原子确保一件事:不会发生数据争用.也就是说,访问变量不会使您的计算机爆炸.

Formally, atomics ensures one thing: there will be no data races. That is, accessing the variable will not make your computer explode.

CPU在执行指令时可能会对其重新排序,这意味着指令可能会在硬件级别上重新排序,而与编写程序的方式无关.

CPU might reorder instructions as it is executing them, which means the instructions might get reordered on the hardware level, independent of how you wrote the program.

最后,还有缓存的作用,它们是更快的内存,sorta包含全局内存的部分副本.缓存并不总是同步的,这意味着它们并不总是就正确"的内容达成共识.不同的线程可能没有使用相同的缓存,因此,它们可能在变量具有的值上不一致.

Finally there are effects of caches, which are faster memory that sorta contains a partial copy of the global memory. Caches are not always in sync, meaning they don't always agree on what is "correct". Different threads may not be using the same cache, and due to this, they may not agree on what values variables have.

以上内容几乎就是C ++在此问题上所说的:除非明确地另有说​​明,否则每条指令的副作用顺序是完全不明确的.从不同的线程看,它甚至可能不一样.

What the above surmounts to is pretty much what C++ says about the matter: unless explicitly stated otherwise, the ordering of side effects of each instruction is totally and completely unspecified. It might not even be the same viewed from different threads.

形式上,将副作用排序的保证称为 happens-before 关系.除非副作用先于,否则不会.松散地,我们只是说它叫做同步.

Formally, the guarantee of an ordering of side effects is called a happens-before relation. Unless a side effect happens-before another, it is not. Loosely, we just say call it synchronization.

现在, memory_order_relaxed 是什么?它告诉编译器停止干预,但不必担心CPU和缓存(以及可能的其他事情)的行为.因此,为什么您看到不可能"的断言的一种可能是

Now, what is memory_order_relaxed? It is telling the compiler to stop meddling, but don't worry about how the CPU and cache (and possibly other things) behave. Therefore, one possibility of why you see the "impossible" assert might be

  1. 线程1将 20 存储到 y ,然后将 10 存储到 x 到其缓存.
  2. 线程2读取新值,并将 10 y 存储到其缓存中.
  3. 线程3不从线程1读取值,而是读取线程2的值,然后断言失败.
  1. Thread 1 stores 20 to y and then 10 to x to its cache.
  2. Thread 2 reads the new values and stores 10 to y to its cache.
  3. Thread 3 didn't read the values from thread 1, but reads those of thread 2, and then the assert fails.

这可能与现实中发生的事情完全不同,关键是任何事情都可能发生.

This might be completely different from what happens in reality, the point is anything can happen.

要确保多次读写之间的先于先后的关系,请参见 Brian的答案.

To ensure a happens-before relation between the multiple reads and writes, see Brian's answer.

提供先发生关系的另一个构造是 std :: mutex ,这就是为什么它们没有这种精神错乱的原因.

Another construct that provides happens-before relations is std::mutex, which is why they are free from such insanities.

这篇关于对原子类感到困惑:memory_order_relaxed的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆