`
noble510520
  • 浏览: 53250 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

从源代码到Runtime发生的重排序

阅读更多

 源代码和Runtime时执行的代码很可能不一样,这是因为编译器、处理器常常会为了追求性能对改变执行顺序。然而改变顺序执行很危险,很有可能使得运行结果和预想的不一样,特别是当重排序共享变量时。

 从源代码到Runtime需要经过三步的重排序:

重排序过程

编译器重排序

 为了提高性能,在不改变单线程的执行结果下,可以改变语句执行顺序。

 比如尽可能的减少寄存器的读写次数,充分利用局部性。像下面这段代码这样,交替的读x、y,会导致寄存器频繁的交替存储x和y,最糟的情况下寄存器要存储3次x和3次y。如果能让x的一系列操作一块做完,y的一块做完,理想情况下寄存器只需要存储1次x和1次y。

//优化前
int x = 1;
int y = 2;
int a1 = x * 1;
int b1 = y * 1;
int a2 = x * 2;
int b2 = y * 2;
int a3 = x * 3;
int b3 = y * 3;

//优化后
int x = 1;
int y = 2;
int a1 = x * 1;
int a2 = x * 2;
int a3 = x * 3;
int b1 = y * 1;
int b2 = y * 2;
int b3 = y * 3;

指令重排序

 指令重排序是处理器层面做的优化。处理器在执行时往往会因为一些限制而等待,如访存的地址不在cache中发生miss,这时就需要到内存甚至外存去取,然而内存和外区的读取速度比CPU执行速度慢得多。

 早期处理器是顺序执行(in-order execution)的,在内存、外存读取数据这段时间,处理器就一直处于等待状态。现在处理器一般都是乱序执行(out-of-order execution),处理器会在等待数据的时候去执行其他已准备好的操作,不会让处理器一直等待。

 满足乱序执行的条件:

  1. 该缓存的操作数缓存好
  2. 有空闲的执行单元

 对于下面这段汇编代码,操作1如果发生cache miss,则需要等待读取内存外存。看看有没有能优先执行的指令,操作2依赖于操作1,不能被优先执行,操作3不依赖1和2,所以能优先执行操作3。
所以实际执行顺序是3>1>2

LDR R1, [R0];//操作1
ADD R2, R1, R1;//操作2
ADD R3, R4, R4;//操作3

内存系统重排序

 由于处理器有读、写缓存区,写缓存区没有及时刷新到内存,造成其他处理器读到的值不是最新的,使得处理器执行的读写操作与内存上反应出的顺序不一致

 如下面这个例子,可能造成处理器A读到的b=0,处理器B读到的a=0。A1写a=1先写到处理器A的写缓存区中,此时内存中a=0。如果这时处理器B从内存中读a,读到的将是0。

 以处理器A来说,处理器A执行的顺序是A1>A2>A3,但是由于写缓存区没有及时刷新到内存,所以实际顺序为A2>A1>A3。

初始化:
a = 0;
b = 0;

处理器A执行
a = 1; //A1
read(b); //A2

处理器B执行
b = 2; //B1
read(a); //B2

处理器和内存的交互

阻止重排序

 不论哪种重排序都可能造成共享变量中线程间不可见,这会改变程序运行结果。所以需要禁止对那些要求可见的共享变量重排序。

  • 阻止编译重排序:禁止编译器在某些时候重排序。
  • 阻止指令重排序和内存系统重排序:使用内存屏障或Lock前缀指令
1
0
分享到:
评论

相关推荐

    最新Ehlib 5.2.84(含完整源代码,支持delphi XE)

    本版本含完整源代码,支持以下 IDE: Delphi 5,6,7,2005 C++Builder 5,6 BDS 2006 (Delphi 2006, C++Builder 2006) Delphi 2007 RAD Studio 2009 (Delphi 2009, C++Builder 2009) Embarcadero RAD Studio 2010 ...

    DevExpress ExpressQuantumGrid Suite v5.9 Full Source

    从标准二维表格到 runtime分组、栏目定制,从主体/细节关系到卡片浏览,从XP主题到自由模式...它专门为你的开发需求而设计,助你赢得市场。主要特点多数据模式快速数据装入基于结构的浏览主从关系自动数据分组无限...

    易语言模块914个

    runtime.ec RUN加减模块1.0+名.ec SAVEPIC.EC SetIEProxy.ec setuser.ec sev.ec SHELL32.EC ShutDown.ec SH_RAR.EC SIMIXP.EC simixp1.0.ec simixp1.01.ec simixp1.02.ec simixp3.0.ec simixp4.0.ec ...

    net学习笔记及其他代码应用

    引用可以转换到接口类型或从接口类型转换,instanceof 运算符可以用来决定某对象的类是否实现了接口。 [Page] 39.启动一个线程是用run()还是start()? 答:启动一个线程是调用start()方法,使线程所代表的虚拟处理机...

    asp.net知识库

    SQL过程自动C#封装,支持从表到基本存储过程生成 使用SQLDMO控制 SQL Server 使用SQL-DMO实现定制SQL Scripts Create Tables and Build inserts from Tables by using Mygeneration Templates(Sql Server) C# 获取...

    Eclipse权威开发指南2.pdf

    4.2.9 将程序与源代码相关联..... 123 4.2.10 热代码替换..... 123 4.3 远程调试...... 124 4.4 练习概述...... 125 4.5 本章小结...... 126 4.6 参考文献...... 127 第5章 协同使用Eclipse 129 5.1 Eclipse对CVS的...

    C#微软培训资料

    18.2 在 C #代码中调用 C++和 VB 编写的组件 .240 18.3 版 本 控 制 .249 18.4 代 码 优 化 .252 18.5 小 结 .254 第五部分 附 录 .255 附录 A 关 键 字.255 附录 B 错 误 码.256 附录 C .Net 名字空间...

    Eclipse权威开发指南3.pdf

    4.2.9 将程序与源代码相关联..... 123 4.2.10 热代码替换..... 123 4.3 远程调试...... 124 4.4 练习概述...... 125 4.5 本章小结...... 126 4.6 参考文献...... 127 第5章 协同使用Eclipse 129 5.1 ...

    Eclipse权威开发指南1.pdf

    4.2.9 将程序与源代码相关联..... 123 4.2.10 热代码替换..... 123 4.3 远程调试...... 124 4.4 练习概述...... 125 4.5 本章小结...... 126 4.6 参考文献...... 127 第5章 协同使用Eclipse 129 5.1 ...

    图片下载「Image Downloader」-crx插件

    您可以在此处找到源代码:https://github.com/vdsabev/image-downloader Image Downloader =================如果您需要从网页批量下载图像,使用此扩展程序,您可以:-查看页面包含的图像以及链接到的图像-按宽度,...

    790个易模块打包下载-2

    runtime.ec SAVEPIC.EC SetIEProxy.ec sev.ec Bios信息.ec Cool皮肤模块.ec CPU占用率检测模块.ec DLL注入模块.ec edb到html-1.0.ec edb数据库转Excel模块 1.3.ec ETimeFly API模块.ec HTTP访问模块1.0....

Global site tag (gtag.js) - Google Analytics