The volatile keyword was devised to prevent compiler optimizations that might render code incorrect in the presence of certain asynchronous events.
以前看过volatile的解释,但实际上事情是怎么发生的,心里还是没底。俗话说,眼见为实,要实验证实一下,就要看生成的汇编代码是什么样子的。我用的是VC6,下面是具体的实验步骤:
写一个文件,比如:testvolatile.cpp,内容如下:
void dosomething(){
}
void thread1( int& status)
{
status = 1;
if(status>0){
dosomething();
}
}
void thread2(int& status )
{
status = 0;
}
放在一个工程里,选择Relase版,打开工程设置,在C/C++标签里, 选择Category:Optimizations,选择Maximize Speed, 再选择Category:Listring Files,把Listing file type: 设成Assembly-Only Listing (于是可以生成asm文件,当然选择Assembly with code也可以)。
为什么不用Debug版?因为Debug版不会做代码优化,也就看不出问题。
设置好了,编译testvolatile.cpp,在./Release目录里生成了:testvolatile.asm文件。用文本方式打开,可以看到后面的内容:
...
; Line 6
mov eax, DWORD PTR _status$[esp-4]
mov DWORD PTR [eax], 1
; Line 9
jmp ?dosomething@@YAXXZ ;
dosomething
?thread1@@YAXAAH@Z ENDP ;
...
可以看到,dosomething()是无条件被执行的,不管status是多少。
现在把thread1的输入参数改成volatile:
void thread1( volatile int& status)
重新编译,打开汇编文件,看到:
; Line 6
mov eax, DWORD PTR _status$[esp-4]
mov DWORD PTR [eax], 1
; Line 8
mov ecx, DWORD PTR [eax]
test ecx, ecx
jle SHORT $L270
; Line 9
jmp ?dosomething@@YAXXZ ;
dosomething
$L270:
; Line 11
ret 0
?thread1@@YAXACH@Z ENDP ;
...
这里如代码所希望的,根据变量status的值来选择是否要调用dosomething()。
比较这两个汇编文件,发现编译器会根据变量值来优化条件语句,在多线程下需要考虑volatile的使用。
testvolatile.cpp的意思是:
thread1() 和thread2()可能被不同线程调用,thread1里可能会做一些别的工作,然后才走到if(status>0)语句,根据status当前值来选择是否dosomething();这其实是两个线程根据status来同步工作。
P.S., volatile 和mutex的用途有所不同。mutex可以用来保证线程函数的同步,比如在thread1()或其他函数里加mutex锁,可以让多线程进入这些函数时串行等待。而这里的status是为了让多个线程能够同时工作,然后在一定阶段进行同步的判断和处理。