前言:
C++新标准坤引入了新的线程感知的内存模型。
内存模型精确的定义了基础构建单元应当如何运转。
多数人会忽略内存模型,因为平时只需要借助互斥保护数据并采用条件变量、future、线程闩、线程卡来触发信号,就足以将多线程运用自如。
只有当我们尽力“贴近计算机底层硬件”,内存模型的精确细节的重要作用才会彰显。
原子类型及其操作提供了底层同步操作的功能,其常常只需要一两条CPU指令即可实现。
1. 内存模型基础
内存模型关键:基本结构和并发。
基本结构:整个程序在内存中的布局。它对并发很重要,尤其是在分析底层原子操作的时候。
基本结构 = 对象 + 内存区域。
1.1 对象和内存区域
C++程序的数据全部都由对象构成。对象存放在内存区域,访问对象即是访问内存区域。
位域(bit-field)也叫位段。所谓"位域",实际上就是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。其主要优点当然就是节省内存了~
struct data {
int i;
double d;
int bf1:25;
int bf2:0;
int i2;
char c1,c2;
std::string str;
}
1.2 并发与对象
并发中的竞争,是由于改成共享数据(对象和其内存区域)产生的。要避免竞争 就必须强制线程按照一定的顺序来访问。这个顺序是可以固定不变的(必须先读再写,写完再读)也可以是随着软件的运行而间隔轮换变换访问的次序。
访问次序的实现有两种方法:一种互斥,通过锁定相关互斥来保证每次仅有一个线程访问内存区域。另一种是原子操作的同步性质,在目标内存区域采用原子操作,强制两个线程遵从一定的访问次序。
1.3 改动序列
必须先读再写,写完再读。
只要某线程看到过某个对象,则该线程的后续读操作必须获取相对新的值,并且,该线程的后续写操作,必然出现在改动序列后方,先更新值再去写。
在程序内容,对于同一个对象,全部线程都必须就其形成相同的改动序列,并且在所有的对象上都要求如此,多个对象上的改动序列只是相对关系,线程之间不必达成一致。



