栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

c++11中的atomic与执行顺序问题的讨论

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

c++11中的atomic与执行顺序问题的讨论


这篇文章是看了其他人的博客文章和查阅一些资料自己总结推断的,如有不同看法,欢迎留言分享。

乱序成因:

程序乱序执行的原因有3个:

1、编译器优化

2、处理器优化

3、存储系统

编译器优化其实就是编译器由于某些标准,在编译过程中做出了优化,从而导致程序重排,这个问题就不详细讨论了,重点放在处理器优化和存储系统上。

处理器优化

现代CPU大多数采用流水线技术实现的。简单来看一个 CPU 指令的运行周期可以分成 4 个阶段:取址、译码、执行、写回。这4个阶段都是分别由CPU中的4个相互独立的物理单元来处理。这样子就可以实现一个CPU指令取址完开始译码,下一个CPU指令就可以开始取址而不用等待第一个CPU指令运行完。

当多个指令有依赖关系的时候,例如a指令的运行依赖于b指令的结果,那么a指令必须等待b指令完成写回后才能开始取址,而且流水线会停止,直到b指令写回完成。如果存在一个c指令不依赖于a指令也不依赖于b指令,那么处理器优化就可以把c指令重排到a指令之前,这样子有利于减少流水线停止来等待b指令完成的时间。

存储系统

这里涉及到缓存一致性协议MESI、store buffer与invalidate queue的概念。这里有一篇文章可以作为参考:关于MESI、store buffer与invalidate queue

理解了上述概念后,就能理解程序为什么会乱序执行了,那么怎么解决呢?答案是内存屏障。

内存屏障可以使得屏障前后的指令不被编译器优化和处理器优化重排。

对于读屏障,运行时,读屏障之前的已经加入到store buffer的修改操作会被标记,如果store buffer的所有修改操作还未收到回复而清空掉,那么读屏障之后的修改操作就会加入到store buffer中,cache中对应的缓存行还是原来的值而不是store buffer的值。

对于写屏障,运行时,写屏障之后的操作要在invalidate queue的内容全部处理完(把对应的cache中的缓存行失效)之后才能运行。

atomic原子操作的内存顺序选项std::memory_order_acquire就是相当于在操作之前加一个读屏障,std::memory_order_release就相当于在操作之后加一个写屏障。这样子,就能解决程序乱序问题了。

关于CAS操作的讨论

由于CAS操作需要读出真正的原子变量的值,而且这个过程中是原子的,所以需要通过mesi来保证对应缓存行的一致。无论CAS操作的内存顺序选项什么,CAS操作的原子变量在各个cpu中的缓存行都是一致的。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1019579.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号