阅读:2442回复:2
天书夜读拾遗 ------ volatile的使用
天书夜读拾遗 ------ volatile的使用
volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改。 用volatile关键字声明的变量i每一次被访问时,执行部件都会从i相应的内存单元中取出i的值。 没有用volatile关键字声明的变量i在被访问的时候可能直接从cpu的寄存器中取值(因为之前i被访问过,也就是说之前就从内存中取出i的值保存到某个寄存器中),之所以直接从寄存器中取值,而不去内存中取值,是因为编译器优化代码的结果(访问cpu寄存器比访问ram快的多)。 以上两种情况的区别在于被编译成汇编代码之后,两者是不一样的。之所以这样做是因为变量i可能会经常变化,保证对特殊地址的稳定访问。 让我们来看看下面的程序 #include "stdafx.h" #include "process.h" //volatile int flag =0; int flag =0; void func(void * null) { flag =1; } int _tmain(int argc, _TCHAR* argv[]) { _beginthread(func,0,0); while (1) { if (flag ==1) { break; } } return 0; } 这段代码在DEBUG 模式下没有问题,可以正常退出,但在RELEASE模式下,却发生死循环,问题在哪里呢? 让我们来看看汇编代码 ; Listing generated by Microsoft (R) Optimizing Compiler Version 14.00.50727.762 TITLE i:\VmTech\test\test\test.cpp .686P .XMM include listing.inc .model flat INCLUDELIB OLDNAMES PUBLIC ?flag@@3HA ; flag EXTRN @__security_check_cookie@4:PROC EXTRN __beginthread:PROC ?flag@@3HA DD 01H DUP (?) ; flag PUBLIC ?func@@YAXPAX@Z ; func ; Function compile flags: /Ogtpy ; File i:\vmtech\test\test\test.cpp _TEXT SEGMENT _null$ = 8 ; size = 4 ?func@@YAXPAX@Z PROC ; func ; 11 : flag =1; mov DWORD PTR ?flag@@3HA, 1 ; flag ; 12 : } ret 0 ?func@@YAXPAX@Z ENDP ; func _TEXT ENDS PUBLIC _wmain ; Function compile flags: /Ogtpy _TEXT SEGMENT _argc$ = 8 ; size = 4 _argv$ = 12 ; size = 4 _wmain PROC ; 15 : _beginthread(func,0,0); push 0 push 0 push OFFSET ?func@@YAXPAX@Z ; func call __beginthread mov eax, DWORD PTR ?flag@@3HA ; flag add esp, 12 ; 0000000cH $LL3@wmain: ; 16 : ; 17 : while (1) ; 18 : { ; 19 : if (flag ==1) cmp eax, 1 jne SHORT $LL3@wmain ; 20 : { ; 21 : break; ; 22 : } ; 23 : } ; 24 : return 0; xor eax, eax ; 25 : } ret 0 _wmain ENDP _TEXT ENDS END 可以看到在VC打开完全优化以后,把变量放入EAX后所有的判断均只访问寄存器,而不再从内存中取,导致即使我们在另外的线程 中对该变量进行了修改,可还是没有用。所以以防万一还是在变量前加上volatile关键字,强制让其从内存中读取为好。 一篇小东西,也算是天书夜读的一篇拾遗,呵呵。 |
|
|
沙发#
发布于:2008-10-17 11:44
啊哈 知道有这回事了 不过我没有书
|
|
板凳#
发布于:2008-10-18 09:02
还在等书,等拿到书再仔细看……
|
|
|