volatile只保证其“可见性”,不保证其“原子性”。
执行count++;这条语句由3条指令组成:
(1)将 count 的值从内存加载到 cpu 的某个 寄存器r;
(2)将 寄存器r 的值 +1,结果存放在 寄存器s;
(3)将 寄存器s 中的值写回内存。
所以,如果有多个线程同时在执行 count++,在某个线程执行完第(3)步之前,其它线程是看不到它的执行结果的。(这里有疑惑:线程同时执行count++,为了保证其原子性,为何不加mutex lock?而是寻求volatile?)
在没有volatile的时候,执行完count++,执行结果其实是写到CPU缓存中,没有马上写回到内存中,后续在某些情况下(比如CPU缓存不够用)再将CPU缓存中的值flush到内存。因为没有存到内存里,其他线程是不能及时看到执行结果的。
在有volatile的时候,执行完count++,执行结果写入缓存中,并同时写入内存中,所以可以保证其它线程马上看到执行的结果。
1 int some_int = 100; 2 3 while(some_int == 100) 4 { 5 //your code 6 }
这时候,编译器会优化代码为:
1 //your code
因为编译器认为some_int没被改变过,一直是100。但是在多线程时,如果执行完第一行,但是还没执行到第三行时,另一个线程修改了some_int,while就不能进入循环了。加了volatile后,阻止了编译器优化,每次读到some_int会从内存中读取,而不是本线程的寄存去(当然这会损失效率)。这就是volatile的作用。