多线程互斥访问全局变量的问题 一全局变量va,在线程tha中有如下操作: va++;在线程thb中有如下操作: if(va>SomeValue){ ... }对变量va是否要加互斥锁?有哪些方法 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 CMutex m_Mutex;m_Mutex.Lock();if(va>SomeValue){}m_Mutex.UnLock(); 我认为这样简单的操作没有必要加互斥。原因是,从汇编角度来考虑,++一个数的值只需要一条机器码,而读取一个int型变量的值其最终代码也只是1条代码,所以呢没必要 感觉有必要,因为 变量 可能放在寄存器和内存中,可能会导致dirty read,哈,初学,请多指教; 问题在于块if(va>SomeValue){...}是不是作为一个原子操作。 如果va是整型,我认为完全没有必要如果是双精度浮点数,还是互斥的好因为双精度时,if(va>SomeValue)语句是几句组成的,执行到一半的时候可能被改变了va的值,这样就会导致比较语句判断失误。 首先,Semigod说的有道理。不过想指正一下,“简单的操作没有必要加互斥”的说法可能不太准确。“任何一个线程对全局变量都实现的是原子操作的话,可以不加互斥操作。”这样说也许更严密一点。“++一个数的值只需要一条机器码,而读取一个int型变量的值其最终代码也只是1条代码,所以呢没必要。” 的确,汇编语言中有和高级语言相似的递增,递减指令。(例如:80x80系列的INC,DEC指令) 但我们的编译器真的会向我们想象中的那样,使“++”等于“INC”吗? 让实践来检验吧。下边是VC++6.0下,一段C++程序的反汇编信息:... ...119: int Var1;120: Var1 = 0;00401973 C7 45 E4 00 00 00 00 mov dword ptr [ebp-1Ch],0121:122: Var1++;0040197A 8B 55 E4 mov edx,dword ptr [ebp-1Ch]0040197D 83 C2 01 add edx,100401980 89 55 E4 mov dword ptr [ebp-1Ch],edx123: ...... ...(注:这里的例子是局部变量的情况,全局变量类似)至于双精度型,或if语句,大家也可以自己检验一下。正像我们看到的,编译器并没有实现我们的想法。所以,在Bill没有使他的编译器“更聪明”之前,我们最好还是加上互斥操作比较安全。Shinka2007.07.17 使用Mutex或者临界区都比较占资源,可以参考使用InterlockedIncrement 怎么在一个线程里面对队列对象(queue)push()数据,另外一个线程pop()..下面代码为什么不行呢? 在主函数main.cpp中定义全局变量,然后把全局变量q作为参数传递给两个线程类的构造函数..queue<char*> q; CRITICAL_SECTION pLock; //线程全局变量main(){ InitializeCriticalSection(&pLock); new Thread1( q); new Thread2(q);}在thread1.cpp中..在这个线程中把push数据进入队列,extern CRITICAL_SECTION pLock; //线程全局变量在main.cpp中定义void __fastcall captureThread::Execute(){ while(true) { .... /*这里把接收到的数据放入一个公共的数据包缓冲池,这个缓冲池是一个LILO的队列 */ EnterCriticalSection(&lock); q.push(RecvBuf); LeaveCriticalSection(&lock); }}在thread2.cpp中,把queue中的数据每处理一个以后就pop出来..extern CRITICAL_SECTION pLock; //线程全局变量在main.cpp中定义void __fastcall ProcessPacket::Execute(){ while(true) { if( processQueue.empty()) { //printf("empty"); continue; } EnterCriticalSection(&lock); buf=q.front(); processQueue.pop(); LeaveCriticalSection(lock); /*--------------------------------*/ DecodeIpPack(buf);//处理来自队列的数据 }}还是有问题:如果在thread1中push数据,而在在thread2中根本没有数据可pop().... 首先,你需要确定你使用的queue支持多线程,应该是在link的选项中。或者如下:第一个线程:EnterCriticalSection(&lock);q.push(RecvBuf);SetEvent(hPushEvent);LeaveCriticalSection(&lock);第二个线程:while(TRUE){if(WAIT_OBJECT_0!=WaitForSingleObject(hPushEvent,INFINITE)) break;EnterCriticalSection(&lock); buf=q.front(); processQueue.pop(); LeaveCriticalSection(lock);试试看,没有多想,还应该有更好的方式,但更好的方式取决于你对问题的理解和对技术的平衡 整形变量当然用 InterlockedIncrement MSDN都这么说.va++ 需要编译器进行优化,不一定保证单指令就执行完毕.如果考虑多CPU,HT之类的,那就更加当然用InterlockedIncrement 了 大家都用啥东西打开TXT之类的文本? 怎样将树形列表框中信息保存到文件 如何实现信息提示? 请问大家,怎样可以更改PE可执行文件的图标? CSocket的send函数可否改成非阻塞的,这种情况用什么send好啊 1,如何取得远程主机内存的使用情况 2,如何设置远程主机的系统时间,up有分 win下面有什么可以把一个网站下载下来的工具,在线等 如何实现文本显示时的动态移动? 关于socket,菜鸟的我没搞懂 。。。??? 小问题:当改变listctrl的大小时,怎样重排他的icons? 请教一个调试 warning 。 请问如何在一个对话框中建立一个Splitter window?
m_Mutex.Lock();
if(va>SomeValue){}m_Mutex.UnLock();
if(va>SomeValue){...}
是不是作为一个原子操作。
如果是双精度浮点数,还是互斥的好
因为双精度时,if(va>SomeValue)语句是几句组成的,执行到一半的时候可能被改变了va的值,这样就会导致比较语句判断失误。
首先,Semigod说的有道理。不过想指正一下,“简单的操作没有必要加互斥”的说法可能不太准确。“任何一个线程对全局变量都实现的是原子操作的话,可以不加互斥操作。”这样说也许更严密一点。“++一个数的值只需要一条机器码,而读取一个int型变量的值其最终代码也只是1条代码,所以呢没必要。”
的确,汇编语言中有和高级语言相似的递增,递减指令。(例如:80x80系列的INC,DEC指令)
但我们的编译器真的会向我们想象中的那样,使“++”等于“INC”吗?
让实践来检验吧。下边是VC++6.0下,一段C++程序的反汇编信息:... ...
119: int Var1;
120: Var1 = 0;
00401973 C7 45 E4 00 00 00 00 mov dword ptr [ebp-1Ch],0
121:
122: Var1++;
0040197A 8B 55 E4 mov edx,dword ptr [ebp-1Ch]
0040197D 83 C2 01 add edx,1
00401980 89 55 E4 mov dword ptr [ebp-1Ch],edx
123: ...
... ...(注:这里的例子是局部变量的情况,全局变量类似)至于双精度型,或if语句,大家也可以自己检验一下。正像我们看到的,编译器并没有实现我们的想法。
所以,在Bill没有使他的编译器“更聪明”之前,
我们最好还是加上互斥操作比较安全。Shinka
2007.07.17
queue<char*> q;
CRITICAL_SECTION pLock; //线程全局变量main()
{
InitializeCriticalSection(&pLock);
new Thread1( q);
new Thread2(q);
}在thread1.cpp中..
在这个线程中把push数据进入队列,extern CRITICAL_SECTION pLock; //线程全局变量在main.cpp中定义void __fastcall captureThread::Execute()
{ while(true)
{
....
/*这里把接收到的数据放入一个公共的数据包缓冲池,这个缓冲池是一个LILO的队列 */ EnterCriticalSection(&lock);
q.push(RecvBuf);
LeaveCriticalSection(&lock);
}}在thread2.cpp中,把queue中的数据每处理一个以后就pop出来..extern CRITICAL_SECTION pLock; //线程全局变量在main.cpp中定义void __fastcall ProcessPacket::Execute()
{ while(true)
{
if( processQueue.empty())
{
//printf("empty");
continue;
} EnterCriticalSection(&lock);
buf=q.front();
processQueue.pop();
LeaveCriticalSection(lock);
/*--------------------------------*/
DecodeIpPack(buf);//处理来自队列的数据
}
}还是有问题:如果在thread1中push数据,而在在thread2中根本没有数据可pop()....
或者如下:
第一个线程:
EnterCriticalSection(&lock);
q.push(RecvBuf);
SetEvent(hPushEvent);
LeaveCriticalSection(&lock);
第二个线程:
while(TRUE){
if(WAIT_OBJECT_0!=WaitForSingleObject(hPushEvent,INFINITE))
break;
EnterCriticalSection(&lock);
buf=q.front();
processQueue.pop();
LeaveCriticalSection(lock);试试看,没有多想,还应该有更好的方式,但更好的方式取决于你对问题的理解和对技术的平衡