并行编程——内存模型之顺序一致性

1  定义

Sequential consistency , 简称 SC,定义如下

… the result of any execution is the same as if the operations of all the processors were executed in some sequential order, and the operations of each individual processor appear in this sequence in the order specified by its program [lamport]

下面用一个小例子说明这个定义的意思:

假设我们有两个线程(线程1和线程2)分别运行在两个CPU上,有两个初始值为0的全局共享变量x和y,两个线程分别执行下面两条指令:

初始条件: x = y = 0;

表 1.1  CC 示意图

线程 1

线程 2

x = 1;

y=1;

r1 = y;

r2 = x;

 因为多线程程序是交错执行的,所以程序可能有如下几种执行顺序:

 表 1.2  CC示意图2

Execution 1

Execution 2

Execution 3

x = 1;

r1 = y;

y = 1;

r2 = x;

结果:r1==0 and r2 == 1

y = 1;

r2 = x;

x = 1;

r1 = y;

结果: r1 == 1 and r2 == 0

x = 1;

y = 1;

r1 = y;

r2 = x;

结果: r1 == 1 and r2 == 1

Execution 1

Execution 2

Execution 3

当然上面三种情况并没包括所有可能的执行顺序,但是它们已经包括所有可能出现的结果了,所以我们只举上面三个例子。我们注意到这个程序只可能出现上面三种结果,但是不可能出现r1==0 and r2==0的情况。

SC其实就是规定了两件事情:
1)每个线程内部的指令都是按照程序规定的顺序(program order)执行的(单个线程的视角)
2)线程执行的交错顺序可以是任意的,但是所有线程所看见的整个程序的总体执行顺序都是一样的(整个程序的视角)

第一点很容易理解,就是说线程1里面的两条语句一定在该线程中一定是x=1先执行,r1=y后执行。第二点就是说线程1和线程2所看见的整个程序的执行顺序都是一样的,举例子就是假设线程1看见整个程序的执行顺序是我们上面例子中的Execution 1,那么线程2看见的整个程序的执行顺序也是Execution 1,不能是Execution 2或者Execution 3。

有一个更形象点的例子。伸出你的双手,掌心面向你,两个手分别代表两个线程,从食指到小拇指的四根手指头分别代表每个线程要依次执行的四条指令。SC的意思就是说:
(1)对每个手来说,它的四条指令的执行顺序必须是从食指执行到小拇指
(2)你两个手的八条指令(八根手指头)可以在满足(1)的条件下任意交错执行(例如可以是左1,左2,右1,右2,右3,左3,左4,右4,也可以是左1,左2,左3,左4,右1,右2,右3,右4,也可以是右1,右2,右3,左1,左2,右4,左3,左4)

其实说简单点,SC就是我们最容易理解的那个多线程程序执行顺序的模型。CC 保证的是对一个地址访问的一致性,SC保证的是对一系列地址访问的一致性。

2  几种顺序约束

顺序的内存一致性模型为我们提供了一种简单的并且直观的程序模型。但是,这种模型实际上阻止了硬件或者编译器对程序代码进行的大部分优化操作。为此,人们提出了很多松弛的(relaxed)内存顺序模型,给予处理器权利对内存的操作进行适当的调整。例如Alpha处理器,PowerPC处理器以及我们现在使用的x86, x64系列的处理器等等。下面是一些内存顺序模型

2.1  TSO (整体存储定序)

  • 数据载入间的执行顺序不可改变。
  • 数据存储间的顺序不可改变。
  • 数据存储同相关的它之前的数据载入间的顺序不可改变。
  • 数据载入同其相关的它之前的数据存储的顺序可以改变。
  • 向同一个地址存储数据具有全局性的执行顺序。
  • 原子操作按顺序执行。
  • 这方面的例子包括x86 TSO26和SPARC TSO.

2.2  PSO (部分存储定序)

  • 数据载入间的执行顺序不可改变。
  • 数据存储间的执行顺序可以改变。
  • 数据载入同数据存储间相对顺序可以改变。
  • 向同一个地址存储数据具有全局性的执行顺序。
  • 原子操作同数据存储间的顺序可以改变。
  • 这方面的例子包括SPARC PSO.

2.3  RMO (宽松内存定序)

  • 数据载入间的顺序可以改变。
  • 数据载入同数据存储间的顺序可以改变。
  • 数据存储间的顺序可以改变。
  • 向同一个地址存储数据具有全局性的执行顺序。
  • 原子操作同数据存储和数据载入间的顺序可以改变。
  • 这方面的例子包括Power27和ARM.7

图 1  一些体系架构的内存顺序标准

 

图 2  强内存顺序模型和弱内存顺序模型一些例子,

最左边的内存顺序一致性约束越弱,右边的约束是在左边的基础上加上更多的约束,X86/64 算是比较强的约束。

 

3  乱序执行和内存屏障

任何非严格满足SC规定的内存顺序模型都产生所谓乱序执行问题,从编程人员的代码,到编译器,到CPU运行,中间可能至少需要对代码次序做三次调整,每一次调整都是为了最终执行的性能更高。如下图

图 3  编译乱序和运行乱序

串行时代,编译器和CPU对代码所进行的乱序执行的优化对程序员都是封装好了的,无痛的,所以程序员不需要关心这些代码在执行时被乱序成什么样子。在单核多线程时代,mutex , semaphore 等机制在实现的时候考虑了编译和执行的乱序问题,可以保证关键代码区不会被乱序执行。在多核多线程时代,大部分情况下跟单核多线程是类似的,通过锁调用可以保证共享区执行的顺序性。但某种情况下,比如自己编写无锁程序,则会被暴露到这个问题面前。

 下面通过一个例子解释乱序执行和内存屏障这两个概念。

[来源:http://preshing.com/20120625/memory-ordering-at-compile-time]

示例代码:

int A, B;

void foo()

{

    A = B + 1;

    B = 0;

}

普通编译选项:

$ gcc -S -masm=intel foo.c

$ cat foo.s

        ...

        mov     eax, DWORD PTR _B  (redo this at home...)

        add     eax, 1

        mov     DWORD PTR _A, eax

        mov     DWORD PTR _B, 0

加上 -o2 优化编译选项,可以看到,B的赋值操作顺序变了

$ gcc -O2 -S -masm=intel foo.c

$ cat foo.s

        ...

        mov     eax, DWORD PTR B

        mov     DWORD PTR B, 0

        add     eax, 1

        mov     DWORD PTR A, eax

        ...

上述情况在某些场景下导致的后果是不可接受的,比如下面这段伪代码中,生产者线程执行于一个专门的处理器之上,它先生成一条消息,然后通过更新ready的值,向执行在另外一个处理器之上的消费者线程发送信号,由于乱序执行,这段代码在目前大部分平台上执行是有问题的:

处理器有可能会在将数据存储到message->value的动作执行完成之前和/或其它处理器能够看到message->value的值之前,执行consume函数对消息进行接收或者执行将数据保存到ready的动作。

图 4  乱序执行

回到之前的例子,加上一句内存屏障命令

int A, B;

 

void foo()

{

    A = B + 1;

    asm volatile("" ::: "memory");

    B = 0;

}

依然采用 o2 优化编译选项,发现这次B的赋值操作顺序没有变化

$ gcc -O2 -S -masm=intel foo.c

$ cat foo.s

        ...

        mov     eax, DWORD PTR _B

        add     eax, 1

        mov     DWORD PTR _A, eax

        mov     DWORD PTR _B, 0

        ...

在内存顺序一致性模型不够强的多核平台上,例子2的正确实现应该是下面这种,需要加上两个内存屏障语句。

图5  内存屏障

X86 的内存屏障 #define barrier() __asm__ __volatile__("": : :"memory")

更多X86内存屏障请参考 : http://blog.csdn.net/cnctloveyu/article/details/5486339

 

转载于:https://www.cnblogs.com/jiayy/p/3246157.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/376490.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

160 - 4 ajj.1

环境: Windows Xp sp3 输入Name和Serial,无错误提示。看说明,只有正确时才有提示 OD载入,搜索字符串,发现两个字符串: Panel1DblClick和Panel1Click 一个双击一个单击 先跟随单击的: 00457…

JS判断是否安装flash player及当前版本

function flashChecker() {var hasFlash 0;     //是否安装了flashvar flashVersion 0;   //flash版本if(document.all) {var swf new ActiveXObject(ShockwaveFlash.ShockwaveFlash);if(swf) {hasFlash 1;VSwf swf.GetVariable("$version");flashVersion…

Daily Scrum 11.18

今日完成任务: 1.在提问问题的时候为问题创建索引 2.解决了修改个人资料后刷新没有更新的问题 3.初步加入了采纳功能(没完善UI设计) 遇到困难:创建索引之后,跳转到主页,需要重新登录,找了半天不…

160 - 5 ajj.2

环境: Windows xp sp3 打开,输入点东西到输入框(这里把第一个输出框称为text1)里面,点一下注册,什么反应都没有。 到处都点一点,每张图片都点一下,还是什么反应都没有。 查壳&…

移动平台WEB前端开发技巧汇总

原名《移动平台3G手机网站前端开发布局技巧汇总》,由武方博整理的,让我们了解下移动设备上的WEB站点开发的基础知识,多些时间和精力去优化其他细节,我这里对原文的标签格式做了细微的调整,阅读查看起来明晰些&#xff…

0809

来自网销协会消息:8月8日,第八届豫商大会新闻发布会在郑州举行,由河南省政协主办,省商务厅、省工商联、省豫商联合会协办,安阳市人民政府承办的第八届豫商大会将于8.28如期举行。本次大会会期两天,其中&…

160 - 6 aLoNg3x.1

环境: Windows xp sp3 查壳,这次不用脱壳了,但是还是Delphi程序。 打开后看随便输点东西进去,发现Nome什么都能输入,但最多10个字符,而 Codice可以是数字或者是“$”,在输入“$”后就可以输入…

hyper-v 用户无法再 创建外部配置存储 0x80070005

windows server 2008R2 刚安装的hyper-v 重启过。 修改配置文件到d:\Hyper-V目录下, hyper-V 创建 服务器遇到错误 操作失败 创建外部配置存储:一般性拒绝访问错误 虚拟机ID 0x80070005 d:\hyper-V 安全权限为 everyone 所有,users 所有,admi…

160 - 7 aLoNg3x.2

环境: Windows Xp sp3 打开程序,看了帮助发现要求还是看到那个logo, 但是这次少了个按钮,真棒! 但是这次的Codice却是什么都可以输入进去了。 查一下壳发现还是Delphi程序。 因为还是Delphi的程序,有了前…

Spring 中的国际化Message的简单例子(ApplicationContext) 不跟框架集成的版本

首先&#xff0c;建立一个描述message的XML文件&#xff0c;名为messages.xml <?xml version"1.0" encoding"UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-bean…

简述进程间通信方式

进程间通信方式通常有共享内存 信号量 消息队列 管道 FIFO Socket等几种。 共享内存的模型&#xff0c;它是最有效率的进程间通信方式进程间信号量是进程间同步主要方式&#xff0c;信号量操作为负的时候&#xff0c;进程阻塞。直到信号量为正 内存映射是一种特殊的共享内存…

辅助的写与数据库交互的XML文件的类

现在企业级WEB应用中与数据库交互的XML文件都是通过插件自动生成的&#xff0c;不过有些时候修改比较老的项目的时候也是需要手动的来做这一动作的&#xff01;如下代码就是一个实现上述的功能的辅助类&#xff0c;在此记录一下以备后用&#xff01; package com.cn.common.uti…

160 - 8 Andrnalin.1

环境&#xff1a; Windows xp sp3 打开&#xff0c;就一个Key输入框&#xff0c;输入&#xff1a;goodname&#xff0c;点OK&#xff0c;弹出一个 不明文字的框&#xff0c;反正肯定不对。 查壳&#xff0c;无壳的vb程序。OD载入&#xff1a; 查找字串&#xff0c;翻到最下…

C++ 虚函数表解析

C 虚函数表解析 陈皓 http://blog.csdn.net/haoel 前言 C中的虚函数的作用主要是实现了多态的机制。关于多态&#xff0c;简而言之就是用父类型别的指针指向其子类的实例&#xff0c;然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”&#x…

160 - 9 Andrnalin.2

环境&#xff1a; Windows xp sp3 打开&#xff0c;这次升级了&#xff0c;有个Name和一个Key&#xff0c;输入&#xff1a; Name&#xff1a;goodname Key&#xff1a;12345678 肯定错误。拿到错误信息的字符串 查壳&#xff0c;无壳的VB程序。 直接OD载入&#xff0c;字…

[PALAPALA] 无题 - 外来的和尚会念经

手机, 现代人响当当的必须品, 尤其在移动App流行的大环境之下显得更为重要. 我, 并不是一个重度依赖手机的机粉. 但我对手机的差异化敏感度很高... 安卓手机, 我不喜欢, 因为满大街泛滥&#xff0c;折腾过多... 苹果手机, 我不喜欢, 因为满大街泛滥&#xff0c;bug过多..... 相…

HTTP协议 (四) 缓存

HTTP协议 (四) 缓存 阅读目录 缓存的概念缓存的好处Fiddler可以方便地查看缓存的header如何判断缓存新鲜度通过最后修改时间&#xff0c;判断缓存新鲜度与缓存相关的headerETag浏览器不使用缓存直接使用缓存&#xff0c;不去服务器端验证如何设置IE不使用缓存公有缓存和私有缓存…

160 - 10 Andrénalin.3

环境&#xff1a; Windows xp sp3 打开&#xff0c;是只有一个key&#xff0c;输入个goodname试试&#xff0c;错误。。。记下错误信息 查壳&#xff0c;无壳的VB程序。 查找字符串&#xff1a; 00402036 UNICODE "kXy^rO|*yXo*m\kMuOn*" 00402090 UNICODE &qu…

160 - 11 Andrnalin.4

环境&#xff1a; Windows xp sp3 打开&#xff0c;这次的界面炫酷多了&#xff0c;就像输保险箱密码。 旁边一个“UNREGISTRIERT”表示还没注册 输入个666666&#xff0c;没反应又没有确认按钮&#xff0c;可以猜测是用timer来检测输入的正确性 查壳&#xff0c;无壳的VB程…

ZooKeeper启动过程2:FastLeaderElection

前一篇文章中说到&#xff0c;启动ZooKeeper集群时&#xff0c;需要分别启动集群中的各个节点&#xff0c;各节点以QuorumPeer的形式启动&#xff0c;最后到达startLeaderElection和lookForLeader。 先说startLeaderElection 首先&#xff0c;初始化节点自身的currentVote【当前…