wowocock
VIP专家组
VIP专家组
  • 注册日期2002-04-08
  • 最后登录2016-01-09
  • 粉丝16
  • 关注2
  • 积分601分
  • 威望1651点
  • 贡献值1点
  • 好评度1227点
  • 原创分1分
  • 专家分0分
阅读:2442回复:2

天书夜读拾遗 ------ volatile的使用

楼主#
更多 发布于:2008-10-16 19:45
天书夜读拾遗 ------ 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关键字,强制让其从内存中读取为好。

一篇小东西,也算是天书夜读的一篇拾遗,呵呵。
附件名称/大小 下载次数 最后更新
test.zip (970KB)  22 2008-10-16 19:45
花开了,然后又会凋零,星星是璀璨的,可那光芒也会消失。在这样 一瞬间,人降生了,笑者,哭着,战斗,伤害,喜悦,悲伤憎恶,爱。一切都只是刹那间的邂逅,而最后都要归入死亡的永眠
boywhp
驱动中牛
驱动中牛
  • 注册日期2007-08-09
  • 最后登录2015-04-24
  • 粉丝2
  • 关注0
  • 积分1105分
  • 威望515点
  • 贡献值0点
  • 好评度254点
  • 原创分1分
  • 专家分0分
沙发#
发布于:2008-10-17 11:44
啊哈 知道有这回事了 不过我没有书
hyjtlyra2009
驱动牛犊
驱动牛犊
  • 注册日期2008-09-10
  • 最后登录2010-07-22
  • 粉丝6
  • 关注0
  • 积分2分
  • 威望323点
  • 贡献值2点
  • 好评度0点
  • 原创分0分
  • 专家分10分
板凳#
发布于:2008-10-18 09:02
还在等书,等拿到书再仔细看……
洗鉴宏宇 兼济豢龙
游客

返回顶部