alf*_*ngj 9 c++ multithreading synchronization c++11
我有以下C++ 2011代码:
std::atomic<bool> x, y;
std::atomic<int> z;
void f() {
x.store(true, std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_release);
y.store(true, std::memory_order_relaxed);
}
void g() {
while (!y.load(std::memory_order_relaxed)) {}
std::atomic_thread_fence(std::memory_order_acquire);
if (x.load(std::memory_order_relaxed)) ++z;
}
int main() {
x = false;
y = false;
z = 0;
std::thread t1(f);
std::thread t2(g);
t1.join();
t2.join();
assert(z.load() !=0);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在我的计算机体系结构类中,我们被告知此代码中的断言始终成立.但经过现在的审查,我无法理解为什么会这样.
据我所知:
如果我的理解是正确的,为什么不能发生以下一系列行动?
y.store(true, std::memory_order_relaxed);被称为我认为这符合'获取' - '发布'规则,但是,例如在这个问题的最佳答案:理解c ++ 11内存栅栏,这与我的情况非常相似,它暗示我的步骤1动作序列不能在'memory_order_release'之前发生,但是由于其背后的原因没有详细说明.
我对此感到非常困惑,如果有人能说清楚它会很高兴:)
每种情况下具体发生的情况取决于您实际使用的处理器。例如,x86 可能不会对此断言,因为它是一个缓存一致性架构(您可以有竞争条件,但是一旦一个值从处理器写入缓存/内存,所有其他处理器都会读取该值 -当然,不会阻止另一个处理器立即写入不同的值,等等)。
因此,假设它在 ARM 或类似的处理器上运行,但不能保证其本身具有缓存一致性:
因为写入x是在 之前完成的memory_order_release,所以 t2 循环不会退出,while(y...)untilx也为 true。这意味着x稍后读取时,它保证为1,因此z被更新。我唯一的疑问是,您是否也不需要releasefor z...如果在与和main不同的处理器上运行,那么中可能仍然有一个过时的值。t1t2zmain
当然,如果您有一个多任务操作系统(或者只是做了足够多的事情的中断等),则不能保证会发生这种情况 - 因为如果运行 t1 的处理器刷新其缓存,那么 t2 很可能会读取 x 的新值。
正如我所说,这不会对 x86 处理器(AMD 或 Intel 处理器)产生这种影响。
因此,一般性地解释屏障指令(也适用于 Intel 和 AMD 处理器):
首先,我们需要了解,虽然指令可以无序地开始和结束,但处理器确实对顺序有一般的“理解”。假设我们有这个“伪机器代码”:
...
mov $5, x
cmp a, b
jnz L1
mov $4, x
Run Code Online (Sandbox Code Playgroud)
L1:……
处理器可以mov $4, x在完成“jnz L1”之前推测性地执行 - 因此,为了解决这个事实,处理器必须回滚已执行mov $4, x的情况jnz L1。
同样,如果我们有:
mov $1, x
wmb // "write memory barrier"
mov $1, y
Run Code Online (Sandbox Code Playgroud)
处理器有规则规定“不要执行在 wmb 之后发出的任何存储指令,直到完成之前的所有存储”。这是一条“特殊”指令——它的精确目的是保证内存排序。如果不这样做,你的处理器就坏了,设计部门的某个人就“命悬一线”。
同样,“读内存屏障”是处理器设计者保证处理器不会完成另一次读取的指令,直到我们完成屏障指令之前的待处理读取。
只要我们不致力于“实验性”处理器或某些无法正常工作的劣质芯片,它就会以这种方式工作。这是该指令定义的一部分。如果没有这样的保证,就不可能(或者至少极其复杂且“昂贵”)实现(安全)自旋锁、信号量、互斥体等。
通常还存在“隐式内存障碍”——也就是说,即使没有内存障碍,也会导致内存障碍的指令。软件中断(“INT X”指令或类似指令)往往会这样做。
| 归档时间: |
|
| 查看次数: |
669 次 |
| 最近记录: |