C++11 内存模型详解(2)

如果一个线程A对一块内存 m 以 release 的方式进行修改,那么在线程 A 中,所有在该 release 操作之前进行的内存操作,都在另一个线程 B 对内存 m 以 acquire 的方式进行读取之后,变得可见。

举个粟子,假设线程 A 执行如下指令:

a.store(3); b.store(4); m.store(5, release);

线程 B 执行如下:

e.load(); f.load(); m.load(acquire); g.load(); h.load();

如上,假设线程 A 先执行,线程 B 后执行, 因为线程 A 中对 m 以 release 的方式进行修改, 而线程 B 中以 acquire 的方式对 m 进行读取,所以当线程 B 执行完 m.load(acquire) 之后, 线程 B 必须已经能看到 a == 3, b == 4.

以上死板的描述事实上还传达了额外的不那么明显的信息:

release 和 acquire 是相对两个线程来说的,它约定的是两个线程间的相对行为:如果其中一个线程 A 以 release 的方式修改公共变量 m, 另一个线程 B 以 acquire 的方式时读取该 m 时,要有什么样的后果,但它并不保证,此时如果还有另一个线程 C 以非 acquire 的方式来读取 m 时,会有什么后果。

一定程度阻止了乱序的发生,因为要求 release 操作之前的所有操作都在另一个线程 acquire 之后可见,那么:

release 操作之前的所有内存操作不允许被乱序到 release 之后。

acquire 操作之后的所有内存操作不允许被乱序到 acquire 之前。

而在对它们的使用上,有几点是特别需要注意和强调的:

release 和 acquire 必须配合使用,分开单独使用是没有意义。

release 只对写操作(store) 有效,对读 (load) 是没有意义的。

acquire 则只对读操作有效,对写操作是没有意义的。

现代的处理器通常都支持一些 read-modify-write 之类的指令,对这种指令,有时我们可能既想对该操作 执行 release 又要对该操作执行 acquire,因此 c++11 中还定义了 memory_order_acq_rel,该类型的操作就是 release 与 acquire 的结合,除前面提到的作用外,还起到了 memory barrier 的功能。

sequential consistency

sequential consistency 相当于 release + acquire 之外,还加上了一个对该操作加上全局顺序的要求,这是什么意思呢?

简单来说就是,对所有以 memory_order_seq_cst 方式进行的内存操作,不管它们是不是分散在不同的 cpu 中同时进行,这些操作所产生的效果最终都要求有一个全局的顺序,而且这个顺序在各个相关的线程看起来是一致的。

举个粟子,假设 a, b 的初始值都是0:

线程 A 执行:

a.store(3, seq_cst);

线程 B 执行:

b.store(4, seq_cst);

如上对 a 与 b 的修改虽然分别放在两个线程里同时进行,但是这多个动作毕竟是非原子的,因此这些操作地进行在全局上必须要有一个先后顺序:

先修改a, 后修改 b,或

先修改b, 把整个a。

而且这个顺序是固定的,必须在其它任意线程看起来都是一样,因此 a == 0 && b == 4 与 a == 3 && b == 0 不允许同时成立。

后话

这篇随笔躺在我的草稿箱里已经半年多时间了,半年多来我不断地整理在这方面的知识,也在不断理清自己的思路,最后还是觉得关于内存模型有太多可以说却不是一下子能说得清楚的东西了,因此这儿只能把想说的东西一减再减,把范围缩小到 C++11 语言层面上作简单介绍,纯粹算是做个总结,有兴趣深入了解更多细节的读者,我强烈推荐去看一下 Herb Sutter 在这方面做的一个 talk, 内存模型方面的知识是很难理解,更难以正确使用的,在大多数情况下使用它而得到的些少性能优势,已经完全不值得为此而带来的代码复杂性及可读性方面的损失,如果你还在犹豫是否要用这些相对底层的东西的时候,就不要用它,犹豫就说明还有其它选择,不到没得选择,都不要亲自实现 lock free 相关的东西。

C++11新特性:Lambda函数(匿名函数) 

C++ Primer Plus 第6版 中文版 清晰有书签PDF+源代码

读C++ Primer 之构造函数陷阱

读C++ Primer 之智能指针

读C++ Primer 之句柄类

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/7323f39e1703e2d46613c3b521f8fd17.html