Weak vs. Strong Memory Models

来源:互联网 发布:夏威夷果 知乎 编辑:程序博客网 时间:2024/06/03 12:41
SEP 30, 2012

http://preshing.com/20120930/weak-vs-strong-memory-models/


正文开始--->

Memory reordering有很多种类型,并不是每一种reordering都经常发生。这完全依赖于你所面向的processor,以及你开发时使用的工具。

一个memory model(内存模型)告诉你,对于一个processor或者开发工具,相对于你编写的源码,在运行时可能发生什么类型的memory reordering。记住,仅当使用lock-free编程时memory reordering的影响才会体现出来。

学习memory model也有一小段时间了——绝大部分都是读各种网络文章,然后通过实验验证——我已经有所收获,并把它们分类成了如下的4类。每一种memory model除了完全提供它左边的那个model的所有保证,还能提供更多。我在weak和strong memory model之间画了一条清晰的线,这也符合大部分人使用这些术语的习惯。


图上面的每一种物理设备代表了一种hardware memory model。一个hardware memory model告诉你相对汇编(或者机器)语言代码,在运行期会发生什么样的memory reordering。

在memory reordering上,每一种processor家族都有不同的习性,这些习性仅在多核或者多处理器配置中才能体现出来(multicore or multiprocessor)。现在多核是流行趋势,所以有必要熟悉它们。

对应的,还有software memory model。比如当你使用C/C++或者Java写下可移植的lock-free代码时,通常仅仅需要考虑software memory model。
无论如何,对hardware memory model有一个大概的了解并不难。它可以帮助你解释debug时那些未预期的行为,以及——可能非常重要的——知道有些不正确的代码在某些processor和编译工具下正常运行仅仅是因为运气成分。

Weak Memory Models

对于最弱的那种memory model,可能会碰到在前面代码控制类比中提到过的所有4种memory reordering。任何store和load都可能和其它的store和load重排序,只要没有修改单线程程序的行为。在实际中,reordering可能是因为compiler 对指令的reordering,或者processor自己的memory reordering。

如果一个processor是weak hardware memory model,我们倾向于说它是weakly-ordered或者weak ordering。我们可能也说它有一个relaxed memory model(松弛的内存模型)。对weakly-ordered processor,人们最喜欢举的例子就是DEC Alpha。实在是没有其它的主流processor是weaker ordering的了。

C11和C++11暴露了一个weak software memory model,可能就是因为受到了Alpha的影响。当使用这些语言的底层atomic操作时,你是否真的面向一个类似x86/64的strong processor是无关紧要的。就像我前面证明的,你依然必须指明正确的memory ordering限制,如果只是为了阻止compiler reordering。

Weak With Data Dependency Ordering

虽然Alpha处理器已经不常见了,我们依然有好几种现代CPU家族,继续保持了weak hardware ordering的传统:
> ARM, 移动设备的主流处理器
> PowerPC,这个是Xbox360的主流平台
> Itanium,Linux和HP Server还在支持

这些家族的memory model基本上和Alpha一样弱,除了一个程序员特别关注的细节:它们保持了data dependency ordering。什么意思?这意味着,如果你在C/C++中写A->B,你可以保证读取到的B至少和A一样新。而Alpha则不能保证这个。这里我不想在data dependency ordering上做深入的挖掘,除了提醒一点:Linux RCU机制严重依赖它。

Strong Memory Models

让我们先看看hardware memory model,strong和weak之间的区别到底是什么?实际上对这个问题还有不同的观点(见这个文章:http://herbsutter.com/2012/08/02/strong-and-weak-hardware-memory-models/#comment-5903)。但是我认为80%的情况下,大部分人认为的都是同一回事。因此,我想先提出下面的定义:
—————————————————————————————-
一个strong hardware memory model就是,每一个machine Instruction都潜在的遵守acquire and release语义。因此,当一个CPU core执行一系列的writes时,所有其它CPU core都会按照它们被写入的顺序看到这些值的改变。
—————————————————————————————-
不难想象,现在想象一下对代码控制类比的一个改进,所有提交到共享内存的修改都是有序的(没有StoreStore重排序),从共享内存的读也是有序的(没有LoadLoad重排序),并且所有指令都是按顺序执行的(没有LoadStore重排序)。然而StoreLoad重排序,还是存在的。


基于上面的定义,x86/64 processor家族通常是strongly-ordered。也有一些情况下,x86/64的strong ordering保证会丢失,但是大部分情况下,作为应用程序员,我们可以忽略。一个x86/64 processor确实会乱序执行指令,但是这是硬件实现的细节——重要的是它依然保持了内存指令是有序的,所以在multicore环境中,我们依然认为它是strong-ordered。在历史上,由于evolving sepc的存在,会导致一些小困惑。

显然SPARC processors,在运行在TSO模式下时,是另一个strong hardware ordering的例子。TSO指的是“total store order”,它和我上面给出的定义有一些细微的差别。它意味着,所有core对共享内存的写一直有单一的全局的顺序。x86/64也有这个属性,见Intel x86/64架构规范的卷3,第8.2.3.6-8小结的一些例子。我能说的是,TSO不足以引起对编写底层lock-free的程序员的兴趣,但是它是迈向sequential consistency的一步。

Sequential Consistency

在一个sequential consistent的memory model中,没有memory reordering的存在。好像就是整个程序执行退化成了每个线程之间指令的顺序交叉。特别的前面例子中的r1=r2=0的结果在这里是不可能出现的。

现在,你不可能找到一个在硬件层面保证sequential consistency的多核处理器。然而,历史上有过,那就是1989年的Intel 386。

无论如何,在使用高级程序语言时,sequential consistency仅在software memory model中是令人感兴趣的。在Java5或者更高版本,你可以受用volatile关键字,在C++11,在使用atomic操作时,你可以使用默认的顺序限制:memory_order_seq_cst。如果你这样做,就会限制compiler rereading,并生成相应memory barrier的CPU指令。这样,即使在weakly-ordered 多核设备上,你可以模拟一个sequential consistent的memory model。如果你读过Herlihy&Shavit的The Art of Multiprocessor Programming,一定要注意,它们的例子都假设在一个consequential consistent的software memory model。

Further Details

有关memory model还有其它的很多细节,但是根据我的经验,在编写应用程序级别的lock-free代码时它们用处也不大。比如control dependency,causal consistency,已经不同的内存类型。后面可能还会有更多有关这4种类型的讨论。

如果你真想了解有关processor memory model的更多细节,以及把formal logic当饭吃(形式逻辑),你可以看看剑桥大学的一些工作分享。Paul McKenney对他们的工作和相关工具已经写了一些介绍。
http://www.cl.cam.ac.uk/~pes20/weakmemory/
http://lwn.net/Articles/470681/
(我想一般人就算了)


0 0
原创粉丝点击