C++ std::memory_order 解释

解决问题:

在std::atomic操作中需要对memory_order进行定义。用来解决当线程内的指令执行顺序对于多线程的影响问题。

原子操作就是对一个内存上变量(或者叫左值)的读取-变更-存储(load-add-store)作为一个整体一次完成。在于以这个原子操作为中心,其前后的代码。这些代码并不一定需要是原子操作。编译器对代码可能进行指令重排。也就是说,编译器编译之后(特别是开了优化之后)的代码执行顺序,是不一定严格按照你写代码的顺序的。

CPU执行指令的顺序,也不见得是完全严格按照机器码的顺序。特别是,当代CPU的IPC(每时钟执行指令数)一般都远大于1,也就是所谓的多发射,很多命令都是同时执行的。比如,当代CPU当中(一个核心)一般会有2套以上的整数ALU(加法器),2套以上的浮点ALU(加法器),往往还有独立的乘法器,以及,独立的Load和Store执行器。Load和Store模块往往还有8个以上的队列,也就是可以同时进行8个以上内存地址(cache line)的读写交换。

所谓的memory order,其实就是限制编译器以及CPU对单线程当中的指令执行顺序进行重排的程度(此外还包括对cache的控制方法)。这种限制,决定了以atom操作为基准点(边界),对其之前的内存访问命令,以及之后的内存访问命令,能够在多大的范围内自由重排(或者反过来,需要施加多大的保序限制)。从而形成了6种模式。它本身与多线程无关,是限制的单一线程当中指令执行顺序。但是(合理的)指令执行顺序的重排在单线程环境下不会造成逻辑错误而在多线程环境下会,所以这个问题的目的是为了解决多线程环境下出现的问题

内存一致模型

  •         序列连贯sequential consistency
    • 在每个处理器内,维护每个处理器的程序次序;
    • 在所有处理器间,维护单一的表征所有操作的次序。对于写操作W1, W2, 不能出现从处理器 P1 看来,执行次序为 W1->W2; 从处理器 P2 看来,执行次序却为 W2->W1 这种情况。
      1. 这使得内存操作需要表现为原子执行(瞬发执行):可以想象系统由单一的全局内存组成,每一时刻,由switch将内存连向任意的处理器,每个处理器按程序顺序发射(issue)内存操作。这样,switch就可以提供全局的内存串行化性质。
  • 放松内存一致性模型Relaxed consistency model
    • 放松对程序次序的要求:这种放松与此前所述的“在无缓存的体系结构中采用的优化”类似,仅适用于对不同地址的操作对(opeartion pairs)间使用。
    • 放松对写原子性的要求:一些模型允许读操作在“一个写操作未对所有处理器可见”前返回值。这种放松仅适用于基于缓存的体系结构

C++11 述了 6 种可以应用于原子变量的内存次序, 3种内存模型:

  • sequential consistent(memory_order_seq_cst)
    • SC作为默认的内存序,是因为它意味着将程序看做是一个简单的序列。如果对于一个原子变量的操作都是顺序一致的,那么多线程程序的行为就像是这些操作都以一种特定顺序被单线程程序执行。从同步的角度来看,一个顺序一致的 store 操作 synchroniezd-with 一个顺序一致的需要读取相同的变量的 load 操作。除此以外,顺序模型还保证了在 load 之后执行的顺序一致原子操作都得表现得在 store 之后完成。非顺序一致内存次序(non-sequentially consistency memory ordering)强调对同一事件(代码),不同线程可以以不同顺序去执行,不仅是因为编译器可以进行指令重排,也因为不同的 CPU cache 及内部缓存的状态可以影响这些指令的执行。但所有线程仍需要对某个变量的连续修改达成顺序一致。。

  • relaxed(memory_order_seq_relax).
    • 在原子变量上采用 relaxed ordering 的操作不参与 synchronized-with 关系。在同一线程内对同一变量的操作仍保持happens-before关系,但这与别的线程无关。 在 relaxed ordering 中唯一的要求是在同一线程中,对同一原子变量的访问不可以被重排/

  • acquire release(memory_order_consume, memory_order_acquire, memory_order_release, memory_order_acq_rel),
    • Acquire-release 中没有全序关系,但它 供了一些同步方法。在这种序列模 型下,原子 load 操作是 acquire 操作(memory_order_acquire), 原子 store 操作是 release操作(memory_order_release), 原子read_modify_write操作(如fetch_add(), exchange())可以是 acquire, release 或两者皆是(memory_order_acq_rel). 同步是 成对出现的,它出现在一个进行 release 操作和一个进行 acquire 操作的线程间。 一个 release 操作 syncrhonized-with 一个想要读取刚才被写的值的 acquire 操作。

参考:

https://www.zhihu.com/question/24301047/answer/1193956492
https://www.zhihu.com/question/24301047/answer/83422523

  • 18
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值