volatile关键字后续学习

在上一篇转载中学习了volatile关键字的用处:

一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。

关键在于两个地方:     
 
1. 编译器的优化  (请高手帮我看看下面的理解)

在本次线程内, 当读取一个变量时,为提高存取速度,编译器优化时有时会先把变量读取到一个寄存器中;以后,再取变量值时,就直接从寄存器中取值;
当变量值在本线程里改变时,会同时把变量的新值copy到该寄存器中,以便保持一致

2. 多线程的使用
当变量在因别的线程等而改变了值,该寄存器的值不会相应改变,从而造成应用程序读取的值和实际的变量值不一致
当该寄存器在因别的线程等而改变了值,原变量的值不会改变,从而造成应用程序读取的值和实际的变量值不一致  


下面是我在利用上篇中的小例子进行测试(以下测试均在visual studio 2008环境下)


1. 在没有使用volatile关键字

int _tmain(int argc, _TCHAR* argv[])
{
        //下面i变量没有使用volatile
	int i = 10;              
	int a = i;
	printf("i = %d\n", a);

	//下面汇编语句的作用就是改变内存中i的值,但是又不让编译器知道 
	__asm 
	{ 
		mov dword ptr [ebp-4], 20h 
	}
	int b = i; 
	printf("i = %d\n",b);

	return 0;
}
输出结果:

在debug和release下 结果都是 (与上篇文章有出入啊)
i  = 10
i = 10 

(不会发图片请原谅)

2 使用volatile关键字

int _tmain(int argc, _TCHAR* argv[])
{
        
       //下面i变量没有使用volatile
  volatile int i = 10;int a = i;printf("i = %d\n", a);//下面汇编语句的作用就是改变内存中i的值,但是又不让编译器知道 __asm { mov dword ptr [ebp-4], 20h }int b = i; printf("i = %d\n",b);return 0;}

输出结果:

debug下输出                                       release下输出
i = 10                                            i = 32
i = 10                                            i  = 10
分析原因:

通过对代码的反汇编后发现

1. 在没有使用关键字的时候,release版汇编如下

00401002  in          al,dx 
00401003  push        esi  
	int i = 10;
	int a = i;
	printf("i = %d\n", a);
00401004  mov         esi,dword ptr [__imp__printf (4020A0h)] 
0040100A  push        0Ah  
0040100C  push        offset string "i = %d\n" (4020F4h) 
00401011  call        esi  
00401013  add         esp,8 

	//下面汇编语句的作用就是改变内存中i的值,但是又不让编译器知道 
	__asm 
	{ 
		mov dword ptr [ebp-4], 20h 
00401016  mov         dword ptr [ebp-4],20h 
	}
	int b = i; 
	printf("i = %d\n",b);
0040101D  push        0Ah  
0040101F  push        offset string "i = %d\n" (4020F4h) 
00401024  call        esi  
00401026  add         esp,8 

	return 0;
00401029  xor         eax,eax 
0040102B  pop         esi  
2. 在使用了关键字的debug下
int _tmain(int argc, _TCHAR* argv[])
{
004113A0  push        ebp  
004113A1  mov         ebp,esp 
004113A3  sub         esp,0E4h 
004113A9  push        ebx  
004113AA  push        esi  
004113AB  push        edi  
004113AC  lea         edi,[ebp-0E4h] 
004113B2  mov         ecx,39h 
004113B7  mov         eax,0CCCCCCCCh 
004113BC  rep stos    dword ptr es:[edi] 
	volatile int i = 10;
004113BE  mov         dword ptr [i],0Ah 
	int a = i;
004113C5  mov         eax,dword ptr [i] 
004113C8  mov         dword ptr [a],eax 
	printf("i = %d\n", a);
004113CB  mov         esi,esp 
004113CD  mov         eax,dword ptr [a] 
004113D0  push        eax  
004113D1  push        offset string "i = %d\n" (41573Ch) 
004113D6  call        dword ptr [__imp__printf (4182BCh)] 
004113DC  add         esp,8 
004113DF  cmp         esi,esp 
004113E1  call        @ILT+320(__RTC_CheckEsp) (411145h) 

	//下面汇编语句的作用就是改变内存中i的值,但是又不让编译器知道 
	__asm 
	{ 
		mov dword ptr [ebp-4], 20h 
004113E6  mov         dword ptr [ebp-4],20h 
	}
	int b = i; 
004113ED  mov         eax,dword ptr [i] 
004113F0  mov         dword ptr [b],eax 
	printf("i = %d\n",b);
004113F3  mov         esi,esp 
004113F5  mov         eax,dword ptr [b] 
004113F8  push        eax  
004113F9  push        offset string "i = %d\n" (41573Ch) 
004113FE  call        dword ptr [__imp__printf (4182BCh)] 
00411404  add         esp,8 
00411407  cmp         esi,esp 
00411409  call        @ILT+320(__RTC_CheckEsp) (411145h) 

	return 0;
0041140E  xor         eax,eax 
}
00411410  pop         edi  
00411411  pop         esi  
00411412  pop         ebx  
00411413  add         esp,0E4h 
00411419  cmp         ebp,esp 
0041141B  call        @ILT+320(__RTC_CheckEsp) (411145h) 
00411420  mov         esp,ebp 
00411422  pop         ebp  
00411423  ret              

3. 在使用了关键字release版下
00401002  in          al,dx 
00401003  push        ecx  
00401004  push        esi  
	volatile int i = 10;
	int a = i;
	printf("i = %d\n", a);
00401005  mov         esi,dword ptr [__imp__printf (4020A0h)] 
0040100B  mov         dword ptr [i],0Ah 
00401012  mov         eax,dword ptr [i] 
00401015  push        eax  
00401016  push        offset string "i = %d\n" (4020F4h) 
0040101B  call        esi  
0040101D  add         esp,8 

	//下面汇编语句的作用就是改变内存中i的值,但是又不让编译器知道 
	__asm 
	{ 
		mov dword ptr [ebp-4], 20h 
00401020  mov         dword ptr [i],20h 
	}
	int b = i; 
00401027  mov         eax,dword ptr [i] 
	printf("i = %d\n",b);
0040102A  push        eax  
0040102B  push        offset string "i = %d\n" (4020F4h) 
00401030  call        esi  
00401032  add         esp,8 

	return 0;
00401035  xor         eax,eax 
00401037  pop         esi  
}
00401038  mov         esp,ebp 
0040103A  pop         ebp  
0040103B  ret              


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值