当一个变量定义为 volatile 之后,将具备两种特性:
1.保证此变量对所有的线程的可见性,当一个线程修改了这个变量的值,volatile 保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。这样的话当其他线程要使用这个变量的时候,就会拿到最新更新的值,保证了数据一致性。
比如上面这个例子,running就是一个被volatile修饰的变量,当主线程修改了running的时候,t1线程就会停止,但是当去掉volatile修饰的时候,t1线程就无法得知running在主线程已经被改变,所以也不会停止。
2.禁止指令重排序优化。有volatile修饰的变量,赋值后多执行了一个“load addl $0x0, (%esp)”操作,这个操作相当于一个内存屏障(指令重排序时不能把后面的指令重排序到内存屏障之前的位置),只有一个CPU访问内存时,并不需要内存屏障。
内存屏障:屏障两边的指令不可以重排序!保障有序!
内存屏障共分为四种类型:
类型 | 抽象场景 | 解释 |
LoadLoad屏障 | Load1; LoadLoad; Load2 | Load1 和 Load2 代表两条读取指令。在Load2要读取的数据被访问前,保证Load1要读取的数据被读取完毕。 |
StoreStore屏障 | Store1; StoreStore; Store2 | Store1 和 Store2代表两条写入指令。在Store2写入执行前,保证Store1的写入操作对其它处理器可见 |
LoadStore屏障 | Load1; LoadStore; Store2 | 在Store2被写入前,保证Load1要读取的数据被读取完毕。 |
StoreLoad屏障 | Store1; StoreLoad; Load2 | 在Load2读取操作执行前,保证Store1的写入对所有处理器可见。StoreLoad屏障的开销是四种屏障中最大的。 |
指令重排序:CPU采用了允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理。