首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >memory_order_seq_cst和memory_order_acq_rel有什么不同?

memory_order_seq_cst和memory_order_acq_rel有什么不同?
EN

Stack Overflow用户
提问于 2012-09-10 00:26:27
回答 4查看 11.9K关注 0票数 49

对于这两个操作,存储是释放操作,加载是获取操作。我知道memory_order_seq_cst的目的是对所有操作施加额外的总排序,但我无法构建一个示例,说明如果所有的memory_order_seq_cst都被memory_order_acq_rel取代,情况就不是这样。

我是否遗漏了什么,或者区别只是文档效果,也就是说,如果不打算使用更宽松的模型,那么应该使用memory_order_seq_cst,而在约束宽松模型时使用memory_order_acq_rel

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-09-10 00:45:58

http://en.cppreference.com/w/cpp/atomic/memory_order有一个很好的示例at the bottom,它只适用于memory_order_seq_cst。本质上,memory_order_acq_rel提供相对于原子变量的读写排序,而memory_order_seq_cst提供全局读写排序。也就是说,顺序一致的操作在所有线程中以相同的顺序可见。

这个例子可以归结为:

代码语言:javascript
运行
复制
bool x= false;
bool y= false;
int z= 0;

a() { x= true; }
b() { y= true; }
c() { while (!x); if (y) z++; }
d() { while (!y); if (x) z++; }

// kick off a, b, c, d, join all threads
assert(z!=0);

z上的操作由两个原子变量保护,而不是一个,因此您不能使用获取-释放语义来强制z始终递增。

票数 46
EN

Stack Overflow用户

发布于 2019-09-22 04:39:27

在像x86这样的ISA上,原子映射到屏障,而实际的机器模型包括一个存储缓冲区:

  • seq_cst存储需要刷新存储缓冲区,因此此线程稍后的读取会被延迟,直到存储全局visible.

之后再读取

  • acquirerelease不必刷新存储缓冲区。正常的x86加载和存储本质上具有acq和rel语义。(seq_cst加上一个具有存储转发功能的存储缓冲区。)

但是x86原子RMW操作总是被提升到seq_cst,因为x86 lock前缀是一个完整的内存屏障。其他ISA可以在asm中进行relaxed或acq_rel RMW,商店端可以对以后的商店进行有限的重新排序。(但不是以使RMW看起来非原子的方式:For purposes of ordering, is atomic read-modify-write one operation or two?)

是seq_cst存储和普通发布存储之间区别的一个有启发性的例子。(在x86 asm中,它实际上是mov + mfence与普通mov。实际上,对于在大多数x86 CPU上进行seq_cst存储,xchg是一种更有效的方法,但GCC确实使用了mov+mfence)

有趣的事实:AArch64的LDAR获取-加载指令实际上是一个顺序获取指令,与STLR有一个特殊的交互。直到ARMv8.3LDAPR才能执行简单的获取操作,这些操作可以与早期版本和seq_cst存储(STLR)一起重新排序。(seq_cst加载仍然使用LDAR,因为它们使用need that interaction with STLR来恢复顺序一致性;seq_cstrelease存储都使用STLR)。

使用STLR / LDAR,您可以获得顺序一致性,但只需在下一次LDAR之前清空存储缓冲区,而不是立即在每次seq_cst存储之后执行其他操作。我认为真正的STLR确实是这样实现的,而不是在提交AArch64之前简单地排空存储缓冲区。

通过使用LDAR / STLR将rel或acq_rel增强为seq_cst并不需要很昂贵,除非您seq_cst存储一些内容,然后seq_cst加载其他内容。那么它就和x86一样糟糕了。

其他一些ISA(如PowerPC)有更多的屏障可供选择,可以比mo_seq_cst更便宜地增强到mo_relmo_acq_rel,但它们的seq_cst不能像AArch64那样便宜;seq-cst商店需要一个完整的屏障。

因此,AArch64是seq_cst存储在现场使用特殊指令或屏障指令来排空存储缓冲区的规则的一个例外。ARMv8是在C++11 / Java之后设计的,这并不是巧合,基本上seq_cst是无锁原子操作的缺省设置,所以提高它们的效率很重要。在CPU之后,架构师有几年的时间来考虑提供屏障指令或只是获取/释放与宽松加载/存储指令的替代方案。

票数 11
EN

Stack Overflow用户

发布于 2020-05-19 22:28:58

尝试构建仅具有获取/释放语义的Dekkers或Peterson算法。

这是行不通的,因为获取/释放语义没有提供StoreLoad防护。

在Dekkers算法的情况下:

代码语言:javascript
运行
复制
flag[self]=1 <-- STORE
while(true){
    if(flag[other]==0) { <--- LOAD
        break;
    }
    flag[self]=0;
    while(turn==other);
    flag[self]=1        
}

如果没有StoreLoad围栏,存储可能会跳到负载前面,然后算法就会崩溃。2个线程同时看到另一个锁是空闲的,设置自己的锁并继续。现在在临界区中有2个线程。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12340773

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档