介绍:
重建是重新选择指令序列以优化性能的一种手段。
如果两个操作访问相同的变量,并且这两个操作中的一个具有一个操作作为写作操作,则此时两个操作之间存在数据依赖性。数据依赖项分为三种类型,如表所示:
写作= 1;b = a;编写变量后,阅读此位置并写入a = 1;a = 2;编写变量后,在阅读a = b后编写此变量;b = 1;在阅读变量后,将这三个情况写在此变量之上。只要对两个操作的执行顺序进行排序,将更改程序的执行结果。编译器和处理器的指令序列在单个处理器中执行,并且在单个处理器中执行操作的操作线程,数据依赖性将与Essence(不同处理器和不同线程之间的数据依赖关系”(编译器和处理器都不考虑)。
AS-IF-Serial语义是指:无论如何进行排序,都无法更改单线程执行程序的执行结果。编译器,运行时和处理器必须遵守AS-IF-Serial语义。
为了遵守AS-IF-Serial语义,编译器和处理器不会对数据依赖性的存在进行排序,因为这种重型排序将改变执行结果。但是,如果操作之间没有数据依赖性,则这些操作可以由编译器和处理器分类。
例如,计算圆形区域的代码:
上述三个操作的数据依赖项如下所示:
3个操作之间的依赖性
说明:A和B之间存在数据依赖关系,以及B和B之间的数据依赖关系。因此,在最终的执行指令序列中,C不能将C放到A和B的前部(程序的结果将更改为A和B)的前部。但是,A和B之间没有数据依赖性,并且编译器和处理器可以对A和B之间的执行进行排序。
测序后有以下执行可能性:
摘要:AS-IF-Serial语义栏单线程程序受到保护,遵循AS-IF Serial语义,运行时和处理器的编译器共同为编写单线读取程序的程序员创建错误的幻觉:单线读取程序:单线阅读程序IS IS IS按程序的顺序实现。AS-IF-Serial语义允许单线程序员打扰他们而不必担心排序,也不需要担心内存可见性。
根据以前发生的过程规则,上面计算出的示例代码具有3个hapens-be Forefer-teder-Fore-ted。
在c之前,hapens是从1和2得出的。
尽管在A前实际执行B(在上图中)。请参阅后一个操作,并在第二个操作之前对先前的操作进行排名。在此,B不需要可见的执行结果;并且在重新分组操作A和操作B后的执行结果与Hapens-Before的A和操作B执行的结果一致。在这种情况下,JMM会认为这种重型排序不是违法的,并且JMM运行如此沉重的分类。
在计算机中,软件技术和硬件技术具有共同的目标:在没有更改程序执行结果的前提下,并行性会尽可能改进。编译器和处理区域遵循此目标。从Hapens的定义来看,我们可以看到JMM还遵循了这个目标。
重型排序会影响多线程执行的结果吗?
假定两个线程A和B,第一个执行write()和b execute readr()。螺纹B在执行操作4时执行4时,我可以在1对共享的操作中看到线程A的写入A可变a操作?
答案是:不一定!
由于操作1和操作2没有数据依赖性,因此编译器和处理器可以对这两个操作进行分类。类似的人。
假设操作1和操作2重分类:(虚拟箭头线表示错误的阅读操作)
程序执行序列图
上图的操作1和操作2发生了。执行程序后,线程A首先编写Mark变量标志,然后线程B读取此变量。有条件的判断是正确的。这次,变量A尚未由线程A编写,并且多线程程序的语义被分类和破坏。
假设操作3和操作4重分类:
程序执行序列图
在上述执行方法的过程中,操作3和操作之间存在控制依赖关系。4。代码中有控制依赖性时,指令将影响并行度。出于此原因,编译器和处理器将使用猜测要克服控制相关对并行的影响。以处理器的猜测执行为例,在-Site B上执行的处理器可以提前读取并行计算a*a*a*a,然后计算出结果以将其保存在硬件中CACHE称为记录器缓冲区(ROB)。操作3的条件判断是正确的,请将计算结果写入变量i。
从上图可以看出,猜测操作3和4的实现是分类的。这是多线程程序的语义!
在单线程程序中,由控制依赖控制的操作重新分类不会改变执行结果(这也是AS-IF-Serial语义语义允许其输入控制依赖性操作的原因,可以更改执行程序的结果。
本文总结了“ Java并行编程艺术”,下一篇文章总结了“订单一致性”,因此请继续关注。