我对std::memory_order_acquire
和std::memory_order_release
的理解如下:
acquire 意味着在获取栅栏之后出现的任何存储器访问都不能被重新排序到栅栏之前。
release 意味着在释放栅栏之前出现的任何内存访问都不能被重新排序到栅栏之后。
我不明白的是,为什么在C++11原子库中,获取围栏与加载操作相关联,而释放围栏与存储操作相关联。
为了清楚起见,C++11 <atomic>
库使您能够以两种方式指定内存隔离:您可以将隔离指定为原子操作的额外参数,例如:
x.load(std::memory_order_acquire);
也可以使用std::memory_order_relaxed
并单独指定围栏,如下所示:
x.load(std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_acquire);
我不明白的是,考虑到上面对acquire和release的定义,为什么C++11特别将acquire与load关联起来,将release与存储关联起来?是的,我已经看到了许多例子,展示了如何使用带有释放/存储的获取/加载来在线程之间进行同步,但一般来说,获取屏障(防止语句之后的内存重新排序)和释放屏障(防止语句之前的内存重新排序)的想法与加载和存储的想法是正交的。
那么,为什么,例如,编译器不让我说:
x.store(10, std::memory_order_acquire);
我知道我可以通过使用memory_order_relaxed
,然后使用一个单独的atomic_thread_fence(memory_order_acquire)
语句来完成上述任务,但是,为什么我不能直接对memory_order_acquire
使用store呢
一种可能的用例是,如果我想确保某些存储发生在可能影响其他线程的其他语句执行之前,比如x = 10
。
发布于 2016-04-30 04:37:51
假设我写了一些数据,然后我写了一个指示数据现在已经准备好了。任何其他看到数据准备就绪指示的线程都必须看到数据本身的写入。因此先前写入不能移过该写入。
假设我读到一些数据已经准备好了。在看到数据已经准备好之后,我发出的任何读取都必须在读取之后进行。因此,后续读取不能移动到该读取之后。
因此,当您执行同步写入时,通常需要确保您在此之前执行的所有写入对查看同步写入的任何人都可见。在进行同步读取时,通常必须在同步读取之后执行任何读取操作。
或者,换句话说,acquire通常是读取您可以获取或访问资源的内容,并且后续的读取和写入不能移动到它之前。发布通常是这样写的,即您已经完成了资源,并且之前的写入不能移到它之后。
发布于 2016-05-05 00:17:58
std::memory_order_acquire
栅栏仅确保栅栏之后的所有加载操作不会在栅栏之前的任何加载操作之前重新排序,因此memory_order_acquire
不能确保在执行后续加载时存储对其他线程可见。这就是存储操作不支持memory_order_acquire
的原因,可能需要使用memory_order_seq_cst
来实现存储的获取。
作为一种选择,你可以说
x.store(10, std::memory_order_releaxed);
x.load(std::memory_order_acquire); // this introduce a data dependency
以确保所有加载不会在存储之前重新排序。再说一次,栅栏在这里不起作用。
此外,原子操作中的内存顺序可能比内存围栏更便宜,因为它只确保相对于原子指令的顺序,而不是围栏前后的所有指令。
另请参阅formal description和explanation了解详细信息。
https://stackoverflow.com/questions/36824811
复制相似问题