单个seq_cst加载能否为逐步弱化的原子操作序列提供StoreLoad屏障?
关于Dekker算法变体中内存序的同步问题
线程代码
线程1
RMW(A, seq_cst) load(B, seq_cst) load(C, acquire) load(D, relaxed)
线程2
store(D, relaxed) store(C, release) RMW(B, seq_cst) load(A, seq_cst)
问题背景与疑问
这是Dekker算法的一种变体,我理解两个线程中的seq_cst操作会创建StoreLoad屏障,确保至少有一个线程能看到对方对A或B的修改。
但我更关注C和D的操作:线程1中seq_cst→acquire→relaxed的逐步弱化加载序列,似乎应能与线程2中relaxed→release→seq_cst的逐步强化存储序列正确同步,从而保证若线程1看到B的修改,也能看到C和D的修改。
请问:单个seq_cst加载是否足以阻止整个逐步弱化读取序列的StoreLoad重排序?还是C和D的操作也需设为seq_cst?
回答
结论:无需将C、D改为seq_cst,当前内存序已能保证所需同步
具体解释:
线程2的存储链顺序保证
线程2内的操作遵循线程内先行发生规则:- 即使
store(D)是relaxed语义,同一线程内的写操作不会重排序,因此store(D)必然先于store(C)执行; store(C, release)的release语义确保,线程2中所有在它之前的写操作(包括store(D)),会对后续获取到C的线程可见;RMW(B, seq_cst)作为seq_cst操作,会与线程内之前的所有操作形成先行发生关系,即D、C的写一定先于对B的RMW完成。
- 即使
线程1的加载链同步逻辑
当线程1的load(B, seq_cst)读取到线程2对B的RMW结果时:- 依据seq_cst的全局总序规则,线程2的
RMW(B, seq_cst)先行发生于 线程1的load(B, seq_cst);结合线程2内部的先行发生链,线程2对D、C的写自然也先行发生于线程1的load(B, seq_cst); - 线程1内部,seq_cst加载会阻止后续加载操作被重排序到它之前,因此
load(C)和load(D)不会跑到load(B)前面执行;同时load(C, acquire)与线程2的store(C, release)形成同步对,进一步确保线程1能看到C的写,而D的写因在C之前,也会被线程1可见。
- 依据seq_cst的全局总序规则,线程2的
StoreLoad重排序的影响
不需要担心seq_cst加载是否阻止后续操作的StoreLoad重排序——我们依赖的是先行发生关系链而非单纯的屏障。一旦线程1的seq_cst load(B)看到了线程2的修改,就通过全局总序把线程2的所有前置写操作纳入了线程1的可见范围,后续的load(C)和load(D)无需seq_cst语义也能读取到正确值。
简单总结:线程2的release-store(C)与线程1的acquire-load(C)形成同步对,再加上seq_cst操作的全局同步性,只要线程1看到B的修改,就必然能看到C和D的修改,无需修改C、D的内存序。
内容的提问来源于stack exchange,提问作者tzcnt
相关产品推荐
相关产品推荐

