上一篇博客 volatile关键字总结-CSDN博客,我们讲了两个volatile变量可以限制编译器对指令的重排,但是限制不了cpu层面的指令重排
这篇博客开始,我们演示下cpu层面的指令重排,以及如何禁止cpu层面的指令重排
实验一:复现cpu指令重排
代码如下
#include<iostream>
#include<thread>
using namespace std;
volatile int x = 0;
volatile int y = 0;
volatile int a = 0;
volatile int b = 0;
void threadFun1()
{
// 空循环5万次,这样尽量和线程2同时启动,更容易出现x=0,y=0的结果
for (int i = 0; i < 50000; i++){}
a = 1;
x = b;
}
void threadFun2()
{
b = 1;
y = a;
}
int main()
{
int i = 0;
while (1)
{
i++;
x = y = a = b = 0;
thread t1(threadFun1);
thread t2(threadFun2);
t1.join();
t2.join();
if (x==0 && y == 0)
{
cout << "第" << i << "次执行后,发现x=0,且y=0" << endl;
break;
}
else
{
cout << "第" << i << "次执行后,x=" << x << ",y=" << y << endl;
}
}
return 0;
}
对上面的代码解释下:
1. 四个变量x, y, a, b都用volatile关键字修饰,确保编译器层面不做任何的指令优化
2. 线程1函数中,先执行a=1,再执行x=b
3. 线程2函数中,先执行b=1,再执行y=a
我们每次先把x,y,a,b置零,然后开启这两个线程,按照逻辑,无论线程1先执行,还是线程2先执行,还是线程1,2同时执行,最终两个线程执行完后都不可能出现x=0且y=0的情况
因为出现x=0且y=0,这意味着
要么是 "x=b"先于 "a=1"执行了
要么是 "y=a"限于 "b=1"先执行了
也就是虽然四个变量都使用volatile关键字,但是仍然出现了指令的重排!
实验如下图
第一次执行5万多次出现了,x=0,且y=0的情况
第二次执行11万多次才出现