对于在原子数据类型(例如std::atomic<uint8_t>)的对象上执行的存储,GCC 生成:
MOV释放存储( )情况下的指令std::memory_order_release,XCHG顺序一致存储情况下的指令( std::memory_order_seq_cst)。当目标架构为 x86_64 时。然而,当是ARM64(AArch64)时,在这两种情况下,GCC都会生成相同的指令,即STLRB. 没有生成其他指令(例如内存屏障),Clang 也会发生同样的情况。这是否意味着这条被描述为具有存储-释放语义的指令实际上也提供了顺序一致性?
例如,如果在两个内核上运行的两个线程将执行STLRB不同内存位置的存储,那么这两个存储的顺序是否唯一?这样所有其他线程都保证遵守相同的顺序吗?
我之所以问,是因为根据这个答案,使用acquire-loads ,不同的线程可能会观察到不同的release-store顺序。为了观察相同的顺序,需要顺序一致性。
现场演示: https: //godbolt.org/z/hajMKnd53
我们来看看这个结构:
struct entry {
atomic<bool> valid;
atomic_flag writing;
char payload[128];
}
Run Code Online (Sandbox Code Playgroud)
两个踏板A和B以这种方式同时访问此结构(让它e成为一个实例entry):
if (e.valid) {
// do something with e.payload...
} else {
while (e.writing.test_and_set(std::memory_order_acquire));
if (!e.valid) {
// write e.payload one byte at a time
// (the payload written by A may be different from the payload written by B)
e.valid = true;
e.writing.clear(std::memory_order_release);
}
}
Run Code Online (Sandbox Code Playgroud)
我想这段代码是正确的,并没有出现问题,但我想了解它的工作原理.
引用C++标准(29.3.13):
实现应该使原子存储在合理的时间内对原子载荷可见.
现在,考虑到这一点,想象线程A和B都进入else块.这种交错是否可行?
A并B进入else分支,因为valid是falseA …我从以下网站获取了关于std :: memory_order_seq_cst的示例:http://en.cppreference.com/w/cpp/atomic/memory_order
#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); // …Run Code Online (Sandbox Code Playgroud) 与我之前的问题类似,请考虑以下代码
-- Initially --
std::atomic<int> x{0};
std::atomic<int> y{0};
-- Thread 1 --
x.store(1, std::memory_order_release);
-- Thread 2 --
y.store(2, std::memory_order_release);
-- Thread 3 --
int r1 = x.load(std::memory_order_acquire); // x first
int r2 = y.load(std::memory_order_acquire);
-- Thread 4 --
int r3 = y.load(std::memory_order_acquire); // y first
int r4 = x.load(std::memory_order_acquire);
Run Code Online (Sandbox Code Playgroud)
是怪异的结果 r1==1, r2==0,并r3==2, r4==0有可能在C ++ 11内存模型下,这种情况下?如果我要全部替换std::memory_order_acq_rel成该std::memory_order_relaxed怎么办?
在x86上,这样的结果似乎是被禁止的,请参见此SO问题,但我一般是在询问C ++ 11内存模型。
奖励问题:
我们都同意,与std::memory_order_seq_cst该怪异的结果不会在C ++ 11被允许。现在,赫伯·萨特(Herb Sutter)在他著名的- …
MFENCE。\n\n\n8.2.3.4 可以将早期存储的负载重新排序到不同位置
\n
c.store(relaxed)<--> b.load(seq_cst):https ://stackoverflow.com/a/42857017/1558037
// Atomic load-store\nvoid test() {\n std::atomic<int> b, c;\n c.store(4, std::memory_order_relaxed); // movl 4,[c];\n int tmp = b.load(std::memory_order_seq_cst); // movl [b],[tmp];\n}\nRun Code Online (Sandbox Code Playgroud)\n\n可以重新排序为:
\n\n// Atomic load-store\nvoid test() {\n std::atomic<int> b, c;\n int tmp = b.load(std::memory_order_seq_cst); // movl [b],[tmp];\n c.store(4, std::memory_order_relaxed); // movl 4,[c];\n}\nRun Code Online (Sandbox Code Playgroud)\n\n …