程序员级别的C ++ std :: atomic可以保证什么?

问题描述 投票:8回答:2

我已经听过并阅读了有关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之外。因此,以下任何一种处决都可能发生:

  • T1
  • T1

是吗?

((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问题,我想确保我已经很好地理解了。因为我仍然对...

c++ caching concurrency c++17 atomic
2个回答
3
投票
  1. 是的,没有数据争用

0
投票
关于(3)-取决于所使用的内存顺序。如果存储和RMW操作都使用std::memory_order_seq_cst,则这两种操作都以某种方式排序-即,存储发生在RMW之前,或者相反。如果存储是在RMW之前订购的,则可以保证RMW操作“看到”已存储的值。如果在RMW之后订购存储,则它将覆盖RMW操作写入的值。
© www.soinside.com 2019 - 2024. All rights reserved.