未分类

C++11多线程内存顺序笔记

c++11引入了多线程的支持,我对无锁方面的知识比较感兴趣,重点看原子操作方面的代码。C++11引入了内存秩序(memory order)的概念,看文档(cpprefrencecplusplus)介绍看得云里雾里的,就开始在网上google了一通,有了初步的了解,在这里记录一下:

我认为c++中memory order是对CPU的Memory Ordering语言级别上的声明,它的几个enum常量都有相对应指令。根据wikipedia介绍CPU的内存秩序分为Compile-time和Run-time两类,要避免CPU乱序执行导致的问题需要memory barriers技术。所谓Compile-time的memory barrier就是WilburDing讲的告诉编译器不要随便优化你的代码(而导致内存访问出错)。至于Run-time的情况就不同的CPU有不同的内存秩序模型,在对称多处理系统(SMP)有三种内存一致性模型:

  • Sequential consistency 所有的读写均按顺序执行,它与memory_order_seq_cst相对应,也是最严格内存秩序模型。它是最容易理解的模型,当然这也是有代价的(需要在多核间同步内存数据),相对来说X86/64架构的CPU影响较小,其他类型的CPU要先看过文档再应用这个模型。
  • Relaxed consistency 允许部分读写重排,根据读、写操作的两种操作共有四种排序组合:读后再读可以重排,写后再读可以重排等等。
  • Weak consistency 读写任意重排,仅受限于明确的memory barriers指令。
    大部分SMP架构提供特殊的指令在运行时刷新读写同步,如x86/64架构的fence指令。这也是c++可以出力的地方。

c++中memory_order枚举变量虽然有6种,但是它能表现的内存模型只有三种:Sequential-consistent,Acquire-Release和Relaxed。

  • Sequential-consistent内存模型只用memory_order_seq_cst,对应前面的Sequential consistency
  • Acquire-Release内存模型用了memory_order_consume,memory_order_acquire,memory_order_release和 memory_order_acq_rel。对应前面的Relaxed consistency
  • Relaxed内存模型只用memory_order_relaxed,对应前面Weak consistency(感觉好坑爹,为什么不跟Relaxed consistency对应?)
    这三种模型具体是怎样工作的Dan Maharry有详细解释。

c++的memory_order在microsoft visual c++中实现:只有是否ARM类型的区分:

  • Acquire-Release内存模型在ARM类型的CPU有对应的实现,其他CPU简单转成Sequential-consistent内存模型的调用
  • Relaxed内存模型在非ARM的CPU只是简单的直接读写(所以WilburDing的例子代码在Window系统是OK,如果要保持可移植性最好还是像Dan Maharry那样写代码)。