为什么在多线程中bool变量不需要同步保护,但BOOL就需要同步保护?请高手多提意见.能否汇编代码的角度给俺一个明确的说法,多谢!如果分不够,俺再加!!另外,庆祝CSDN又开放了,恭喜Coder们.哈..........
解决方案 »
- 请问用VC++ 8 写的DLL默认是STDCALL吗?
- 诚心请教各位,关于mfc的几个简单问题
- 右键桌面图标如何在弹出的菜单有自己的应用程序项
- Visual Studio 2003 Visual Studio 2005有什么区别?
- 谁有VC++读取TIFF文件的源程序啊?
- 如果我用SetPixel在框中画了汉字,如何进行获取操作
- 孙鑫 vc网络编程 出现乱码 烫?
- 高分求解:用TreeCtrl显示文件目录当目录有变化时如何自动刷新目录树?
- 有一对话框程序,我在资源中添加了2个菜单资源,id1用于主菜单,id2用于右键单击菜单,
- 如何在客户区中显示变量的值,比如int、double等?
- 请问VoIP较好的论坛有哪些?帮忙推荐,谢谢!
- MFC中如何加入数据文件(。txt)?
static volatile bool isExist;
线程函数类似于:
DWORD ThreadProc(LPVOID)
{
isExist=true;
while(isExist)
{
//do something
}
}
如果不使用volatile,只要while循环不去修改isExist的值,那么编译器会优化全局变量的处理,对于那个线程而言,isExist恒为true;这个代码等价于:
DWORD ThreadProc(LPVOID)
{
isExist=true;
while(true)
{
//do something
}
}
这样一来,别的线程无法控制当前线程的退出。
使用volatile表示变量会不经意地被修改,它告诉编译器不要对此变量作优化。因此isExist将以真实的值呈现出来。
如果按编程的时间来说,我是从1985年开始学习编程的,可能比那位前辈还前辈,我身边很难找到时间更长的“牛人”来问。不过我说的话也不见得是对的,需要你自己来思考和验证。前面已经说了,是否需要同步要视具体应用情况而定。
单任务时代没有同步的概念;单处理器环境如果是原子指令访问变量,可以确保在修改过程中不会运行其它线程,这个可以从汇编角度来解释;汇编指令是在一个处理器中执行的,多处理器环境下已经不能再用汇编来考虑同步问题了。
bool变量只有一位有效,只有0和1两种状态,如果只是要给它赋值而不考虑其值对其它线程的影响,那么可以不用同步。但很多时候程序并非这么简单。
例如:假设你想要用一个bool变量作为线程互斥的开关,同一时间只允许一个线程执行某段代码。通常会想到的做法是:在开始时判断变量的值,当为0时等待重试;当为1时,先把变量设置为0,在执行完这段代码后再把变量设置为1。这种做法就隐藏着问题,因为在判断为1之后,设置为0之前,可能其它线程也会执行到判断变量的地方,由此导致多个线程同时执行了这段代码。
再举个复杂点的例子:当同时执行的多个任务之间存在复杂的逻辑关系时,可能多个线程需要使用同一个bool变量进行逻辑运算(与、或、非、异或等)时,处理器需要先从内存中读出数据,经过运算后再把结果保存回内存中,在运算过程中,其它处理器中运行的线程也可能要对此变量进行类型的运算,如果没有考虑同步,就会产生错误的结果。
而你回的"既然身边有牛人,怎么不直接请教,何必来这里问。", 是在用讨论问题的态度来跟我交流么?我说那些兄弟(可能也包括你)回答帖子不负责任,我说错了么?有用"谁说的"这三个字就算是回答问题的么?如果有兴趣讨论,请摆正你的态度,好么?感激不尽!!
0041151E mov byte ptr [g_bValue (41905Ch)],0
g_bValue ++;
00411525 mov al,byte ptr [g_bValue (41905Ch)]
0041152A mov byte ptr [ebp-0C5h],al
00411530 mov byte ptr [g_bValue (41905Ch)],1 g_nValue = FALSE;
0041157E mov dword ptr [g_nValue (419060h)],0
g_nValue ++;
00411588 mov eax,dword ptr [g_nValue (419060h)]
0041158D add eax,1
00411590 mov dword ptr [g_nValue (419060h)],eax 实际上不bool在这里就是BYTE,BOOL是DWORD,仅仅这个差别而已,如果你一定要对 bool 做加法那么在多线程中还是小心为妙
对于加减法可以使用InterlockedIncrement和InterlockedDecrement来在多线程中保证原子操作
互锁族函数保证增加这个变量值的时候不会被别的线程修改寄存器,考虑如下伪码: mov eax, A
inc eax
mov A, eax 如果这段代码存在于2个任务,task1和task2,然后发生如下调度过程 ;task1执行,设A = 0
mov eax, A
inc eax
;系统切换到task2,保存task1的上下文(包括eax的值,eax = 1)
mov eax, A
inc eax
mov A, eax
;系统切换到task1,保存task2的上下文,恢复的task1的上下文(注意:eax = 1)
mov A,eax 结果A = 1 然而,如果task1和task2顺序执行:
;task1执行,设A = 0
mov eax, A
inc eax
mov A, eax
;系统切换到task2
mov eax, A
inc eax
mov A, eax 结果A = 2
cpu有的是32位,有的是64位。
而BOOL其实是一个DWORD,在32位就是4个字节。
一个汇编指令是一个原子操作,要么成功,要么不成功。
因此在执行一个指令的时候,如果操作数是内存中的4个字节的话,此时别的线程、cpu是无法在此时占用总线的。因此不用加锁。
因此反汇编32位系统上的Interlocked***函数的时候,很多时候你不会看到汇编指令的lock前缀。但增加该前缀总是安全的。
呵呵,多谢兄弟的解释,有点明确了..你说的情况是存在的,所以在这个时候,必须使用同步保护.那么,对于BOOL和bool,在这种情形下,有什么不同么?是不是对BOOL的赋值需要3步,而对bool变量的赋值只需要1步,所以就不需要同步保护了,是不是这个意思?
这位兄弟说的比较明确.但这种情况对于BOOL和bool变量的赋值有什么不同么?
32位CPU,分两种情况。
在结构中,边界对齐为1/2,请保护
普通变量,或边界对齐为4/8,不用保护
多线程读取,使用volatile是明智之举
4个字节必须是按4字节边界对齐的,而且是基本数据类型,在32位机上才可以一个cycle内完成操作。