内存模型的基础知识

从并发的角度来看,内存模型要解答两个问题:

  • 什么是内存位置?

  • 如果两个线程访问相同的内存位置,会发生什么?

内存位置是什么?

引用cppreference.com中对内存位置的定义:

  • 标量对象(算术类型、指针类型、枚举类型或std::nullptr_t),

  • 或非零长度的连续序列。

下面是内存位置的例子:

struct S {
  char a;         // memory location #1
  int b : 5;      // memory location #2
  int c : 11,     // memory location #2 (continued)
        : 0,
      d : 8;      // memory location #3
  int e;          // memory location #4
  double f;       // memory location #5
  std::string g;  // several memory locations
};

首先,对象obj由七个子对象组成,其中b、c两个位字段共享内存位置。

观察上述结构体定义,可以得到如下结论:

  • 每个变量都是一个对象。

  • 标量类型占用一个内存位置。

  • 相邻的位字段(b和c)具有相同的内存位置。

  • 变量至少占用一个内存位置。

那么,到了多线程的关键部分。

两个线程访问相同的内存位置,会发生什么呢?

如果两个线程访问相同的内存位置(相邻位字段共享内存位置),并且至少有一个线程想要修改它,那么程序就会产生数据竞争,除非:

  1. 修改操作为原子操作。

  2. 访问按照某种先行(happens-before)顺序进行。

第二种情况非常有趣,同步语义(如互斥锁)可以建立了先行关系。这些先行关系基于原子建立,当然也适用于非原子操作。内存序(memory-ordering)是内存模型的关键部分,其定义了先行关系的细节。

对内存模型有了初步的认识后,再来看看C++内存模型中定义的“编程协议”。

Last updated