我已经听过并阅读了有关std::atomic
的几篇文章,演讲和stackoverflow问题,我想确保我已经理解得很好。由于MESI(或派生的)高速缓存一致性协议,存储缓冲区,使队列无效等可能存在延迟,因此我仍然对高速缓存行的可见性感到困惑。
我读到x86具有更强的内存模型,并且如果缓存失效被延迟,x86可以还原开始的操作。但是我现在只对我作为C ++程序员应该假定的东西感兴趣,而与平台无关。
[[T1:线程1 T2:线程2 V1:共享的原子变量]
我了解std :: atomic保证,
((1)在变量上不发生数据争用(由于对缓存行的独占访问)。
((2)取决于我们使用哪种memory_order,它(在有障碍的情况下)保证发生顺序一致性(在出现障碍之前,之后或之后出现障碍)。
((3)在T1上进行原子write(V1)之后,在T2上的原子RMW(V1)将是连贯的(其缓存行将已用T1上的写入值进行更新。
但正如cache coherency primer所述,
所有这些事情的含义是,默认情况下,加载可以获取过时的数据(如果相应的失效请求位于失效队列中)
所以,以下正确吗?
((4)std::atomic
不保证T2在T1上进行原子write(V)之后不会读取在原子read(V)上的'陈旧'值。
(4)是否正确:如果在T1上进行原子写入而无论延迟如何,都会使高速缓存行无效,为什么当原子RMW操作而不是在原子读取上,T2等待无效使之生效?
问题(4)是否错误:线程何时可以在执行过程中读取“过时”值并且“可见”?
非常感谢您的回答
更新1
所以看来我在(3)上错了。想象下面的交织,初始V1 = 0:
T1: W(1)
T2: R(0) M(++) W(1)
即使在这种情况下,即使T2的RMW保证完全在W(1)之后发生,它仍然可以读取“陈旧的”值(我错了)。因此,atomic不能保证完全的缓存一致性,而只能保证顺序一致性。
更新2
(5)现在想象这个例子(x = y = 0并且是原子的:]
T1: x = 1;
T2: y = 1;
T3: if (x==1 && y==0) print("msg");
根据我们所说的,看到屏幕上显示的“ msg”不会为我们提供信息,除了在T1之后执行T2之外。因此,以下任何一种处决都可能发生:
是吗?
((6)如果线程始终可以读取'陈旧'的值,如果我们采用典型的“发布”方案,但是我们没有相反地表示某些数据已准备好,而是相反(删除数据),会发生什么?] >
T1: delete gameObjectPtr; is_enabled.store(false, std::memory_order_release); T2: while (is_enabled.load(std::memory_order_acquire)) gameObjectPtr->doSomething();
T2仍然会使用已删除的ptr,直到看到is_enabled为false。
(7)另外,线程可能读取'陈旧'值的事实意味着mutex
不能仅用一个无锁原子权限来实现吗?这将需要线程之间的同步机制。是否需要可锁定的原子?我已经听过并阅读了有关std :: atomic的几篇文章,演讲和stackoverflow问题,我想确保我已经很好地理解了。因为我仍然对...
std::memory_order_seq_cst
,则这两种操作都以某种方式排序-即,存储发生在RMW之前,或者相反。如果存储是在RMW之前订购的,则可以保证RMW操作“看到”已存储的值。如果在RMW之后订购存储,则它将覆盖RMW操作写入的值。