0%

Java并发-指令重排序、指令流水线

如何验证指令发生了重排序?

定义两个变量设置初始值,在两个线程中分别赋新的值,然后打印在赋值语句后面打印另外一个线程修改的变量。

执行很多次,如果发生了打印的都是变量的初始值,就是发生重排序了,违反直觉,但是编译器觉得两条语句没有依赖关系,允许指令重排序

CPU的指令流水线是什么?解决了什么问题?

一条指令可以分为多个步骤完成,每个步骤可以由不同的硬件功能单元来执行,这样就可以让多个功能单元并行执行指令的不同步骤,不需要等待一个指令执行完再执行执行下一个指令,流水线可以让指令的一个步骤完成了就可以执行下一个指令的同一个步骤

CPU指令流水线存在什么问题?

如果指令之间存在数据相关性,导致前一条指令执行完后才能执行后一条指令,指令重叠就会发生冲突,无法并行执行,后面的指令只能等待,这个时候就可以把数据无关的指令重排序,以防止流水线停顿。


CPU指令流水线什么情况下会需要指令重排序?

一条指令可以分为多个步骤完成,如下:

  1. 取指 IF
  2. 译码和取寄存器操作数 ID
  3. 执行或者有效地址计算 EX
  4. 存储器访问 MEM
  5. 写回 WB

CPU在工作时,需要将上述指令分为多个步骤依次执行

为了提高硬件利用率,CPU指令是按流水线技术来执行的,如下:

  1. LW指令 表示 load,其中LW R1,b表示把b的值加载到寄存器R1中
  2. LW R2,c 表示把c的值加载到寄存器R2中
  3. ADD 指令表示加法,把R1 、R2的值相加,并存入R3寄存器中。
  4. SW 表示 store 即将 R3寄存器的值保持到变量a中
  5. LW R4,e 表示把e的值加载到寄存器R4中
  6. LW R5,f 表示把f的值加载到寄存器R5中
  7. SUB 指令表示减法,把R4 、R5的值相减,并存入R6寄存器中。
  8. SW d,R6 表示将R6寄存器的值保持到变量d中

上述便是汇编指令的执行过程,在某些指令上存在X的标志,X代表中断的含义,也就是只要有X的地方就会导致指令流水线技术停顿,同时也会影响后续指令的执行,可能需要经过1个或几个指令周期才可能恢复正常,那为什么停顿呢?这是因为部分数据还没准备好,如执行ADD指令时,需要使用到前面指令的数据R1,R2,而此时R2的MEM操作没有完成,即未拷贝到存储器中,这样加法计算就无法进行,必须等到MEM操作完成后才能执行,也就因此而停顿了,其他指令也是类似的情况。前面阐述过,停顿会造成CPU性能下降,因此我们应该想办法消除这些停顿,这时就需要使用到指令重排了,如下图,既然ADD指令需要等待,那我们就利用等待的时间做些别的事情,如把LW R4,e 和 LW R5,f 移动到前面执行,毕竟LW R4,e 和 LW R5,f执行并没有数据依赖关系,对他们有数据依赖关系的SUB R6,R5,R4指令在R4,R5加载完成后才执行的,没有影响

正如上图所示,所有的停顿都完美消除了,指令流水线也无需中断了,这样CPU的性能也能带来很好的提升,这就是处理器指令重排的作用。