C++ Memory model

Memory model

为C++抽象机,定义计算机内存存储语义。
向C++程序提供的内存是一个或多个连续的字节序列。内存中每一个byte都有独一无二的地址。

Byte

一个byte是内存中最小的可寻址单元。它被定义为一个bits的连续序列,其足够容纳任何UTF-8(256个不同值)编码单元的值和任何basic execution character set(要求为单字节的96个字符)的成员的值。与C类似,C++支持8位字节,或者更大。

类型 char, unsigned charsigned char 使用一字节来进行存储和 value representation. 字节的位数可以通过 CHAR_BIT 或 std::numberic_limits<unsigned char>::digits 来访问。

Memory location

一个 memory location(存储单元) 是

  • 一个 scalar type 对象(算数类型,指针类型,枚举类型,和 std::nullptr_t)
  • 或者非零长度 bit fields 的最大连续序列
    Note: 语言的各种特性,例如 references 和 virtual functions,可能涉及额外的存储单元,它们不能被程序访问,但是由实现进行管理。
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
	struct {
        int ee : 8; // memory location #4
    } e;
} obj; // The object 'obj' consists of 4 separate memory locations

Threads and data races

执行的线程是程序内的控制流,由顶层函数触发,比如std::thread::thread, std::async,或其他方法。

任何线程都能潜在的访问进程中的任意对象(用于自动存储期或线程局部存储期的对象依然可以通过引用或指针被其他线程访问)。

不同的执行线程总是允许同时访问(读或者修改)不同的 memory location,它们之间互不冲突,没有同步需求。

当一个表达式的求值写入到一个 memory location 中时,另一个表达式求值读取或修改相同的 memory location,这个表达式是 conflict 的。一个进程如果由两个相互冲突的表达式求值,它就有数据竞争了,除非:

  • 两个求值执行在相同的线程上或者相同的 signal handler 上,或者
  • 两个冲突的求值是原子操作(见 std::atomic),或者
  • 冲突的表达式之一先于另一表达式执行(见 std::memory_order)
    如果数据竞争发生,则程序的行为是未定义的。

(std::mutex 的释放与另一线程相同mutex的获取是同步进行的,且释放先于获取)

int cnt = 0;
auto f = [&]{cnt++;};
std::thread t1{f}, t2{f}, t3{f}; // undefined behavior
std::atomic<int> cnt{0};
auto f = [&]{cnt++;};
std::thread t1{f}, t2{f}, t3{f}; // OK

Memory order

当线程从一个 memroy location 读取一个值时, 它可能看到初始值,值可能由相同的线程写入,也可能由其他线程写入。参阅 std::memory_order,了解哪条线程的写操作被其他线程可见。

Forward progress

Obstruction freedom

当仅有一条未被标准库函数阻塞的线程执行一个 lock-free 的 atomic function 时,执行能保证完成(所有的标准库lock-free操作都是obstruction-free的)。

lock freedom

当一个或多个 lock-free atomic function 同时执行时,至少其中之一时保证完成的(所有的标准库lock-free操作都是lock-free的,实现的工作是保证它们不能被其他线程无限期的实时锁定,比如通过不断的窃取高速缓存线)

Progress guarantee

在一个合法的C++程序中,每一条线程最终执行下述中的一项:

  • terminate
  • 调用I/O库函数
  • 通过一个 volatile glvalue(泛左值) 执行访问
  • 执行一个原子操作或者同步操作

没有执行线程能够在不执行这些可观察操作的情况下永远执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值