[英]C++ memory_order_acquire/release questions
I recently learn about c++ six memory orders, I felt very confusing about memory_order_acquire
and memory_order_release
, here is an example from cpp:最近了解了 c++ 六个 memory 订单,对
memory_order_acquire
和memory_order_release
感到很困惑,下面是来自 cpp 的示例:
#include <thread>
#include <atomic>
#include <cassert>
std::atomic<bool> x = {false};
std::atomic<bool> y = {false};
std::atomic<int> z = {0};
void write_x() { x.store(true, std::memory_order_seq_cst); }
void write_y() { y.store(true, std::memory_order_seq_cst); }
void read_x_then_y() {
while (!x.load(std::memory_order_seq_cst));
if (y.load(std::memory_order_seq_cst))
++z;
}
void read_y_then_x() {
while (!y.load(std::memory_order_seq_cst));
if (x.load(std::memory_order_seq_cst))
++z;
}
int main() {
std::thread a(write_x);
std::thread b(write_y);
std::thread c(read_x_then_y);
std::thread d(read_y_then_x);
a.join(); b.join(); c.join(); d.join();
assert(z.load() != 0); // will never happen
}
In the cpp reference page, it says:在 cpp 参考页面中,它说:
This example demonstrates a situation where sequential ordering is necessary.
此示例演示了需要顺序排序的情况。
Any other ordering may trigger the assert because it would be possible for the threads c and d to observe changes to the atomics x and y in opposite order.
任何其他排序都可能触发断言,因为线程 c 和 d 可能以相反的顺序观察原子 x 和 y 的变化。
So my question is why memory_order_acquire and memory_order_release can not be used here?所以我的问题是为什么不能在这里使用memory_order_acquire和memory_order_release ? And what semantics does memory_order_acquire and memory_order_release provide?
memory_order_acquire 和 memory_order_release 提供什么语义?
some references: https://en.cppreference.com/w/cpp/atomic/memory_order https://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync一些参考资料: https://en.cppreference.com/w/cpp/atomic/memory_order https://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync
Sequential consistency provides a single total order of all sequentially consistent operations.顺序一致性提供了所有顺序一致操作的单一总顺序。 So if you have a sequentially consistent store in thread A, and a sequentially consistent load in thread B, and the store is ordered before the load (in said single total order), then B observes the value stored by A. So basically sequential consistency guarantees that the store is "immediately visible" to other threads.
因此,如果您在线程 A 中有一个顺序一致的存储,并且在线程 B 中有一个顺序一致的加载,并且存储在加载之前排序(按所述单个总顺序),那么 B 会观察 A 存储的值。所以基本上是顺序一致性保证存储对其他线程“立即可见”。 A release store does not provide this guarantee.
发行商店不提供此保证。
As Peter Cordes pointed out correctly, the term "immediately visible" is rather imprecise.正如 Peter Cordes 正确指出的那样,“立即可见”一词相当不精确。 The "visibility" stems from the fact that all seq-cst operations are totally ordered, and all threads observe that order.
“可见性”源于这样一个事实,即所有 seq-cst 操作都是完全有序的,并且所有线程都遵守该顺序。 Since the store and the load are totally ordered, the value of a store becomes visible before a subsequent load (in the single total order) is executed.
由于存储和加载是完全排序的,因此在执行后续加载(以单个总顺序)之前,存储的值变得可见。
There exists no such total order between acquire/release operations in different threads, so there is not visibility guarantee.不同线程中的获取/释放操作之间不存在这样的总顺序,因此不存在可见性保证。 The operations are only ordered once an acquire-operations observes the value from a release-operation, but there is no guarantee when the value of the release-operation becomes visible to the thread performing the acquire-operation.
只有在获取操作观察到释放操作的值时,操作才会被排序,但不能保证释放操作的值何时对执行获取操作的线程可见。
Let's consider what would happen if we were to use acquire/release in this example:让我们考虑一下如果我们在这个例子中使用获取/释放会发生什么:
void write_x() { x.store(true, std::memory_order_release); }
void write_y() { y.store(true, std::memory_order_release); }
void read_x_then_y() {
while (!x.load(std::memory_order_acquire));
if (y.load(std::memory_order_acquire))
++z;
}
void read_y_then_x() {
while (!y.load(std::memory_order_acquire));
if (x.load(std::memory_order_acquire))
++z;
}
int main() {
std::thread a(write_x);
std::thread b(write_y);
std::thread c(read_x_then_y);
std::thread d(read_y_then_x);
a.join(); b.join(); c.join(); d.join();
assert(z.load() != 0); // can actually happen!!
}
Since we have no guarantee about visibility, it could happen that thread c
observes x == true
and y == false
, while at the same time thread d
could observe y == true
and x == false
.由于我们无法保证可见性,因此线程
c
可能会观察到x == true
和y == false
,而同时线程d
可能会观察到y == true
和x == false
。 So neither thread would increment z
and the assertion would fire.所以两个线程都不会增加
z
并且断言会触发。
For more details about the C++ memory model I can recommend this paper which I have co-authored: Memory Models for C/C++ Programmers For more details about the C++ memory model I can recommend this paper which I have co-authored: Memory Models for C/C++ Programmers
You can use aquire/release when passing information from one thread to another - this is the most common situation.在将信息从一个线程传递到另一个线程时,您可以使用 aquire/release - 这是最常见的情况。 No need for sequential requirements on this one.
不需要对此有顺序要求。
In this example there are a bunch of threads.在这个例子中,有一堆线程。 Two threads make write operation while third roughly tests whether
x
was ready before y
and fourth tests whether y
was ready before x
.两个线程进行写操作,而第三个线程粗略地测试
x
是否在y
之前准备好,第四个线程测试y
是否在x
之前准备好。 Theoretically one thread may observe that x
was modified before y
while another sees that y
was modified before x
.从理论上讲,一个线程可能会观察到
x
在y
之前被修改,而另一个线程会看到y
在x
之前被修改。 Not entirely sure how likely it is.不完全确定它的可能性有多大。 This is an uncommon usecase.
这是一个不常见的用例。
Edit: you can visualize the example: assume that each threads is run on a different PC and they communicate via a network.编辑:您可以可视化该示例:假设每个线程都在不同的 PC 上运行,并且它们通过网络进行通信。 Each pair of PCs has a different ping to each other.
每对 PC 之间都有不同的 ping。 Here it is easy to make an example where it is unclear which event occurred first
x
or y
as each PC will see the events occur in different order.这里很容易举一个例子,其中不清楚哪个事件首先发生在
x
或y
上,因为每台 PC 会看到事件以不同的顺序发生。
I am not sure on sure on which architectures this effect may occur but there are complex ones where two different processors are conjoined.我不确定这种效果可能会发生在哪些架构上,但有一些复杂的架构,其中两个不同的处理器结合在一起。 Surely communication between the processors is slower than between cores of each processor.
当然,处理器之间的通信比每个处理器的内核之间的通信要慢。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.