早期的CPU是通过提高主频来提升CPU的性能,但是随着频率“红利”越来越困难的情况下,厂商开始用多核来提高CPU的计算能力。多核是指一个CPU里有多个核心,在同一时间一个CPU能够同时运行多个线程,通过这样提高CPU的并发能力。

内存一致性模型(memory consistency model)就是用来描述多线程对共享存储器的访问行为,在不同的内存一致性模型里,多线程对共享存储器的访问行为有非常大的差别。这些差别会严重影响程序的执行逻辑,甚至会造成软件逻辑问题。在后面的介绍中,我们将分析不同的一致性模型里,多线程的内存访问乱序问题。

目前有多种内存一致性模型:

  1. 顺序存储模型(sequential consistency model)
  2. 完全存储定序(total store order)
  3. 部分存储定序(part store order)
  4. 宽松存储模型(relax memory order)

一致性模型的特性

在后面我们会分析这几个一致性模型的特性

在分析之前,我们先定义一个基本的内存模型,以这个内存模型为基础进行分析

上图是现代CPU的基本内存模型,CPU内部有多级缓存来提高CPU的load/store访问速度(因为对于CPU而言,主存的访问速度太慢了,上百个时钟周期的内存访问延迟会极大的降低CPU的使用效率,所以CPU内部往往使用多级缓存来提升内存访问效率。)

C1与C2是CPU的2个核心,这两个核心有私有缓存L1,以及共享缓存L2。最后一级存储器才是主存。后面的顺序一致性模型(SC)中,我们会以这个为基础进行描述(在完全存储定序、部分存储定序和宽松内存模型里会有所区别,后面会描述相关的部分)

为了简化描述的复杂性,在下面的内存一致性模型描述里,会先将缓存一致性(cache coherence)简单化,认为缓存一致性是完美的(假设多核cache间的数据同步与单核cache一样,没有cache引起的数据一致性问题),以减少描述的复杂性。

顺序存储模型

顺序存储模型是最简单的存储模型,也称为强定序模型。CPU会按照代码来执行所有的load与store动作,即按照它们在程序的顺序流中出现的次序来执行。从主存储器和CPU的角度来看,load和store是顺序地对主存储器进行访问。

下面分析这段代码的执行结果

在顺序存储器模型里,MP(多核)会严格严格按照代码指令流来执行代码

所以上面代码在主存里的访问顺序是:

S1 S2 L1 L2

通过上面的访问顺序我们可以看出来,虽然C1与C2的指令虽然在不同的CORE上运行,但是C1发出来的访问指令是顺序的,同时C2的指令也是顺序的。虽然这两个线程跑在不同的CPU上,但是在顺序存储模型上,其访问行为与UP(单核)上是一致的。

我们最终看到r2的数据会是NEW,与期望的执行情况是一致的,所以在顺序存储模型上是不会出现内存访问乱序的情况

完全存储定序

为了提高CPU的性能,芯片设计人员在CPU中包含了一个存储缓存区(store buffer),它的作用是为store指令提供缓冲,使得CPU不用等待存储器的响应。所以对于写而言,只要store buffer里还有空间,写就只需要1个时钟周期(哪怕是ARM-A76的L1 cache,访问一次也需要3个cycles,所以store buffer的存在可以很好的减少写开销),但这也引入了一个访问乱序的问题。

首先我们需要对上面的基础内存模型做一些修改,表示这种新的内存模型

相比于以前的内存模型而言,store的时候数据会先被放到store buffer里面,然后再被写到L1 cache里。

首先我们思考单核上的两条指令:

S1:store flag= setS2:load r1=dataS3:store b=set

如果在顺序存储模型中,S1肯定会比S2先执行。但是如果在加入了store buffer之后,S1将指令放到了store buffer后会立刻返回,这个时候会立刻执行S2。S2是read指令,CPU必须等到数据读取到r1后才会继续执行。这样很可能S1的store flag=set指令还在store buffer上,而S2的load指令可能已经执行完(特别是data在cache上存在,而flag没在cache中的时候。这个时候CPU往往会先执行S2,这样可以减少等待时间)

这里就可以看出再加入了store buffer之后,内存一致性模型就发生了改变。

如果我们定义store buffer必须严格按照FIFO的次序将数据发送到主存(所谓的FIFO表示先进入store buffer的指令数据必须先于后面的指令数据写到存储器中),这样S3必须要在S1之后执行,CPU能够保证store指令的存储顺序,这种内存模型就叫做完全存储定序(TSO)。

我们继续看下面的一段代码

在SC模型里,C1与C2是严格按照顺序执行的

代码可能的执行顺序如下:

S1 S2 L1 L2S1 L1 S2 L2S1 L1 L2 S2L1 L2 S1 S2L1 S1 S2 L2L1 S1 L2 S2

由于SC会严格按照顺序进行,最终我们看到的结果是至少有一个CORE的r1值为NEW,或者都为NEW。

在TSO模型里,由于store buffer的存在,L1和S1的store指令会被先放到store buffer里面,然后CPU会继续执行后面的load指令。Store buffer中的数据可能还没有来得及往存储器中写,这个时候我们可能看到C1和C2的r1都为0的情况。

所以,我们可以看到,在store buffer被引入之后,内存一致性模型已经发生了变化(从SC模型变为了TSO模型),会出现store-load乱序的情况,这就造成了代码执行逻辑与我们预先设想不相同的情况。而且随着内存一致性模型越宽松(通过允许更多形式的乱序读写访问),这种情况会越剧烈,会给多线程编程带来很大的挑战。

部分存储定序

芯片设计人员并不满足TSO带来的性能提升,于是他们在TSO模型的基础上继续放宽内存访问限制,允许CPU以非FIFO来处理store buffer缓冲区中的指令。CPU只保证地址相关指令在store buffer中才会以FIFO的形式进行处理,而其他的则可以乱序处理,所以这被称为部分存储定序(PSO)。

那我们继续分析下面的代码

S1与S2是地址无关的store指令,cpu执行的时候都会将其推到store buffer中。如果这个时候flag在C1的cahe中存在,那么CPU会优先将S2的store执行完,然后等data缓存到C1的cache之后,再执行store data=NEW指令。

这个时候可能的执行顺序:

S2 L1 L2 S1

这样在C1将data设置为NEW之前,C2已经执行完,r2最终的结果会为0,而不是我们期望的NEW,这样PSO带来的store-store乱序将会对我们的代码逻辑造成致命影响。

从这里可以看到,store-store乱序的时候就会将我们的多线程代码完全击溃。所以在PSO内存模型的架构上编程的时候,要特别注意这些问题。

宽松内存模型

丧心病狂的芯片研发人员为了榨取更多的性能,在PSO的模型的基础上,更进一步的放宽了内存一致性模型,不仅允许store-load,store-store乱序。还进一步允许load-load,load-store乱序, 只要是地址无关的指令,在读写访问的时候都可以打乱所有load/store的顺序,这就是宽松内存模型(RMO)。

我们再看看上面分析过的代码

在PSO模型里,由于S2可能会比S1先执行,从而会导致C2的r2寄存器获取到的data值为0。在RMO模型里,不仅会出现PSO的store-store乱序,C2本身执行指令的时候,由于L1与L2是地址无关的,所以L2可能先比L1执行,这样即使C1没有出现store-store乱序,C2本身的load-load乱序也会导致我们看到的r2为0。从上面的分析可以看出,RMO内存模型里乱序出现的可能性会非常大,这是一种乱序随可见的内存一致性模型。

内存屏障

芯片设计人员为了尽可能的榨取CPU的性能,引入了乱序的内存一致性模型,这些内存模型在多线程的情况下很可能引起软件逻辑问题。为了解决在有些一致性模型上可能出现的内存访问乱序问题,芯片设计人员提供给了内存屏障指令,用来解决这些问题。

内存屏障的最根本的作用就是提供一个机制,要求CPU在这个时候必须以顺序存储一致性模型的方式来处理load与store指令,这样才不会出现内存访问不一致的情况。

对于TSO和PSO模型,内存屏障只需要在store-load/store-store时需要(写内存屏障),最简单的一种方式就是内存屏障指令必须保证store buffer数据全部被清空的时候才继续往后面执行,这样就能保证其与SC模型的执行顺序一致。

而对于RMO,在PSO的基础上又引入了load-load与load-store乱序。RMO的读内存屏障就要保证前面的load指令必须先于后面的load/store指令先执行,不允许将其访问提前执行。

我们继续看下面的例子:

例如C1执行S1与S2的时候,我们在S1与S2之间加上写屏障指令,要求C1按照顺序存储模型来进行store的执行,而在C2端的L1与L2之间加入读内存屏障,要求C2也按照顺序存储模型来进行load操作,这样就能够实现内存数据的一致性,从而解决乱序的问题。

ARM的很多微架构就是使用RMO模型,所以我们可以看到ARM提供的dmb内存指令有多个选项:

LD load-load/load-storeST store-store/store-loadSY any-any

这些选项就是用来应对不同情况下的乱序,让其回归到顺序一致性模型的执行顺序上去。

本文修改自:http://www.wowotech.net/memory_management/456.html

本人公众号:技术原理君

读取访问权限冲突怎么解决_CPU怎么保证内存访问冲突?一致性?相关推荐

  1. c++ 在Xmemory中,引发了异常: 读取访问权限冲突。 _Pnext 是 0x708

    开发时遇到了这个问题,在Xmemory中,引发了异常: 读取访问权限冲突 通过打断点.prinf输出运行位置都无法定位该错误在何处发生,错误截图如下 最后推断是在析构时发生的异常,特此记录. 解决方法 ...

  2. c++: 读取访问权限冲突0xcdcdcdcd_微信读取不到本地相册

    微信在我们日常生活中经常要使用到,有时候由于设置的不当导致微信无法读取本地相册该如何解决,下面就为大家介绍一下微信读取不到本地相册的解决方法. 微信读取不到本地相册 1.可能是由于您没有打开微信读取本 ...

  3. c++ 读取访问权限冲突_Linux系统利用可执行文件的Capabilities实现权限提升

    一.操作目的和应用场景 Capabilities机制是在Linux内核2.2之后引入的,原理很简单,就是将之前与超级用户root(UID=0)关联的特权细分为不同的功能组,Capabilites作为线 ...

  4. c++ 读取访问权限冲突_关于Windows文件6项基础权限的一些设置!

    之前,我们讨论过设置Windows文件[始终]以图标显示,其实,在Windows中,关于文件的操作还有很多,比如设置文件权限.权限绝对是一个值得深究的话题,为不同的账户设置权限很重要,可以防止重要文件 ...

  5. c++ 读取访问权限冲突_南京课工场IT培训:解析文件共享及访问方式

    各位小伙伴大家好! 我们接上一篇的文件权限操作,接下来和各位小伙伴解析文件共享的操作方法. 我们首先使用管理员身份进入server2016系统,然后对我们之前在E盘中创建的abc的文件夹进行设置,右键 ...

  6. 引发了异常: 读取访问权限冲突。 **pFrame** 是 nullptr。报错解决

    新建MFC文档并引入OCC环境后,在此基础上二次开发时,总是在某次修改代码出错后,出现这种报错,即使是撤回.再打开无BUG版本的备份都还是会有这个报错,网上似乎也没有准确的解答. 于是就抱着试一试的态 ...

  7. 引发了未经处理的异常:读取访问权限冲突_从零开始学Python:23课-文件读写和异常处理

    一下子想起来,我的Python100天教程没更新了,赶紧补上~ 这期就还接着前面的讲哈.另外就是想跟伙伴们了解下,就是跟我要到Python视频教程的伙伴,你们学的怎么样了,可以给我个反馈哈! 实际开发 ...

  8. qt 引发了异常: 写入访问权限冲突。this 是 0x7FF700000000。

    刚刚好像没有搜索到和我出现一样运行报错的帖子,所以记录一下. 但是可惜刚才疯狂出错没有截图,有点懒得退回再截图一遍了.(不要骂我啊我只是记录一下) 再贴一遍vs反馈(没有报错的时候以为成功了结果谁知悲 ...

  9. 异常:写入访问权限冲突

    前言 这次朋友写代码时遇到解决不了的问题.让我帮忙看看.我觉得这个问题还挺好的,所以写下来记录一下,也算是给自己做一个笔记. 异常 引发了未经处理的异常:写入访问权限冲突. The variable ...

  10. 访问权限冲突定义_一文读懂F5 REST API的细粒度角色访问控制

    ↑ 点击上方"小咩社长"关注我 阅读提示|本文大概4718字   阅读需要12分钟 写在前面: 前两天一个保险的客户联系我说有个需求,问通过调用F5 REST API可否实现?: ...

最新文章

  1. java cocoon_Java-跳跃路线
  2. 2019CCPC网络选拔赛签到题题解
  3. Java黑皮书课后题第5章:5.4(将英里转换成千米)编写程序,显示下面的表格(注意:1英里为1.609千米)
  4. C和C++中static的用法及友元
  5. python--文件
  6. 十三种技术文档模板_帮助企业制作帮助文档的6大“黑科技”工具!
  7. C++ 取模、求余运算
  8. 翻译:理解特征工程(2)-分类数据
  9. 理解 this.initialize.apply ( this, arguments )
  10. Cotherm 多物理场耦合方案
  11. python自学第13天之基础数据类型知识点补充
  12. Git在同一台电脑上连接多个仓库
  13. 使用微软Azure的tts文本转语音服务出现java.lang.UnsatisfiedLinkError
  14. 分数加减乘除混合运算带答案_100道题,分数加减法混合运算,要答案
  15. github下载文件时让输入用户名和密码
  16. 零基础入门学习Python 011列表:一个打了激素的数组2
  17. 南开大学20春计算机应用基础在线作业,南开大学20春学期计算机应用基础在线作业参考答案...
  18. afrog 发布新版本 Release 1.3.5 真的想你
  19. 海康威视研究院算法岗实习
  20. QT上位机:局域网特定设备ip查询和显示

热门文章

  1. 成功恢复UNIX误删除数据库文件(NODE已被清除)
  2. 国产APP自动化测试工具AndroidRobot下载地址
  3. go语言的特殊变量 iota
  4. AndroidStudio关联GitHub
  5. js右下角广告[兼容]
  6. 【微软2014实习生及秋令营技术类职位在线測试】题目1 : String reorder
  7. 对sppnet网络的理解
  8. Elasticsearch 单模式下API的增删改查操作
  9. 0302-软件工程第一次作业
  10. Jmeter性能测试之如何写Java请求测试用例类