cpp并发内存模型(一)
作者:互联网
理解了 c++ concurrency in action
5.3.4 小节的内容:Release sequences and synchronizes-with后,对C++ consistency model本质的理解非常有好处.
另外读过lamport 的经典论文Time, Clocks, and the Ordering of Events in a Distributed System
对理解 C++ memory order 也很有好处.
JAVA 与C++ 的内存模型同根同源,都出自与DRF0.
以下是我的理解,有错误地方,请指出,谢谢!
从cpu 角度讲:
- 每个 cpu 按照自己的 clock 在自己世界里独立乱序执行.
- 当某个cpu0对某个原子变量X进行了X.store(a, …)操作,且memory_order的参数不管是什么;然后cpu1 通过X.load(…), 且memory_order 参数不管是什么,如果(不一定立即)cpu1看到了cpu0对X的修改结果a(这期间没有其他cpu修改X), 那么我们一定可以确认 X.store(a) 这个事件一定是发生在X.load() 事件之前(好像是废话,但很重要)。这就好比 lamport 论文中 cpu0 给cpu1 发送了一个消息 ,cpu1 接受了这个消息, 那这个 发送消息事件一定是在接收消息事件之前发生.
- 总结上面两点:每个cpu的运行是各自独立的,一旦两个cpu之间通过对共享原子变量进行操作(至少有一个为store or RMW, 但不能两个都为store)就好比是 一个cpu 发送了消息,一个接受到了这条消息,此时,发送消息这个事件与接受消息这个事件就产生了先后关系,我们可以称为一个同步点(synchronizes point)
从Lock-free 程序设计角度:
- 从Lock-free程序设计角度,我们就是需要借助这个synchronizes point,来同步更多的事件来达到我们想要的memory consistency model.比如C++ Release-Acquire 语义, 我们通过在某个synchronizes point的两端施加相对应的memory barrier(内存栅栏或者内存屏障)这样我们就获得了更多的同步关系,即C++ memory consistency model 的Acquire-Release 语义.
注意:一定要在synchronizes point的两端都要加memory barrier .
memory barrier 从程序员的角度看,是对单个cpu内部 执行内存操作指令顺序的一种局部 限制,而这个synchronizes point 建立了 cpu 之间的一种运行时 先后关系,这样我们就可以获得CPU 之间的更多的先后关系.
- 另外上面的synchronizes point 是在运行期建立的, 即:cpu1在运行过程中确实看到了cpu0对同一原子变量写入的那个值, 则cpu1 与cpu0 在这个时刻的synchronizes point 建立。
另外下面是,我们在设计Lock-Free 程序时,需要注意的:
-
C++ memory consistency model 标准从语义上讲定义的是原子变量操作之间内存可见性的顺序, 并没有保证单个原子变量操作的内存立即可见性.
- 即使是最严格sequentially consistency memory model 的 x.store(a, seq_cst), x.load(seq_cst) 操作, 我们也不能假设x.load(seq_cst) 一定能读到最新值.虽然在具体实现层面(不同平台),会读到x的最新值.
- 如果在特殊应用场景,我们需要保证原子变量立即可见性,则可以根据具体的平台实现,来调用对应的cpu指令。比如在X86 平台上mfence指令;比如BRPC 中对 worksteal queue 的实现.
-
原子变量RMW操作的立即可见性性质。如果cpu0 对x 进行了修改操作(包括RMW), cpu1立即读x(包括RWM),cpu1都不一定能拿到最新值,以下情况除外:cpu0 与 cpu1 对x的操作都是是RMW 操作(比如CAS, fetch_add ), 指定的memory order 任意都可以.
-
synchronizes-with relationship 专指线程之间的关系.happens-before 包括线程内部.
-
原子变量 + memory barrier 实现了memory consistency model语义, 而memory consistency model 语义是 一切上层建筑(锁等)的基础, 比如:unlock-lock 就是满足Release-Acquire 语义,所以在临界区内修改数据就是安全的,且这些数据可以为非原子操作, 因为两个线程不会同时进入临界区,他们好像被限制了执行顺序一样.
-
modification order 的定义:
参考 https://en.cppreference.com/w/cpp/atomic/memory_order
- Release sequence 与synchronizes-with : 参考
c++ concurrency in action
5.3.4
标签:synchronizes,point,cpu0,cpu1,并发,内存,memory,cpp,cpu 来源: https://blog.csdn.net/qq_43325061/article/details/118437115