在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)

摘要:
当您想要终止子线程时,在主线程中:bTerminate=TRUE;WaitForSingleObject;但是,要运行到WaitForSingleObject,子线程会崩溃。如果我们在主线程中等待SingleObject,则主线程将阻塞,这将阻塞消息循环,最终导致工作线程崩溃*_*解决方案:为了解决主线程中的等待问题,Microsoft专门设计了一个函数MsgWaitForMultipleObjects,它可以等待信号和消息。然后,当while循环条件无效时,函数返回,WaitForSingleObject返回。

下面的代码我调试了将近一个星期在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第1张,你能够看出什么地方出了问题吗?

线程函数:

在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第2张DWORD WINAPI ThreadProc(
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第3张    
while(!bTerminate)
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第4张在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第5张    
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第6张{
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第7张        
// 从一个链表中读取信息并且插入到CListCtrl中
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第8张        
// CListCtrl的句柄是通过线程参数传递进来的
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第9张
        for(;;)
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第10张在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第11张       
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第12张{
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第13张           ReadInfoFromList();
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第14张           InsertToCListCtrl();
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第15张        }

在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第16张    }

在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第17张}
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第18张

主线程中使用CreateThread启动线程。

当想终止子线程时,在主线程中:
bTerminate = TRUE;
WaitForSingleObject(threadHandle, INFINITE);
可是,以运行到WaitForSingleObject,子线程就Crash了。

为什么呢?

问题原因:
后来我终于在InsertItem的反汇编中发现了如下的代码
call dword ptr [__imp__SendMessageA@16 (7C141B54h)]
可见,InsertItem是必须借助消息循环来完成任务的。如果我们在主线程中WaitForSingleObject了,必然导致主线程阻塞,也就导致了消息循环的阻塞,最终导致工作线程Crash掉了*_*

解决方案:
为了解决在主线程中Wait的问题,微软专门设计了一个函数MsgWaitForMultipleObjects,这个函数即可以等待信号(thread,event,mutex等等),也可以等待消息(MSG)。即不论有信号被激发或者有消息到来,此函数都可以返回。呵呵,那么我的解决办法也就出来了。
将上面的WaitForSingleObject用下面的代码替换:

在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第19张while(TRUE)
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第20张在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第21张
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第22张{
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第23张
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第24张    DWORD result ; 
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第25张    MSG msg ; 
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第26张
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第27张    result 
= MsgWaitForMultipleObjects(1&readThreadHandle, 
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第28张        FALSE, INFINITE, QS_ALLINPUT); 
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第29张
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第30张    
if (result == (WAIT_OBJECT_0))
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第31张在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第32张    
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第33张{
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第34张        
break;
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第35张    }
 
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第36张    
else 
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第37张在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第38张    
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第39张
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第40张        PeekMessage(
&msg, NULL, 00, PM_REMOVE);
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第41张        DispatchMessage(
&msg); 
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第42张    }
 
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第43张}

在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第44张


总结:
如果在工作线程中有可能涉及到了消息驱动的API,那么不能在主线程中使用WaitForSingleObject一类函数,而必须使用上述的方案。

posted on 2004-07-15 20:22 shootingstars 阅读(13629) 评论(26)  编辑收藏网摘 所属分类: C++

在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)第45张


评论

#1楼 2004-09-17 11:38 HXY [未注册用户]

谢谢你的文章!

  回复  引用    

#2楼 2004-12-10 11:00 Jeff [未注册用户]
太强了,解决了困扰我一整天的问题!!!
  回复  引用    

#3楼 2005-02-27 16:06 world [未注册用户]

作者你好,

消息循环只负责获取消息队列中的消息 ,
SendMessageA的消息并不进入消息队列


  回复  引用    

看了你的文章后,问题解决,非常感谢。
  回复  引用    

#5楼 2005-12-15 17:44 wuzq [未注册用户]
您好!我对你写的内容好奇,于是我就按照你的做法在windows32的console程序,
并没有出现你说的事情,线程依然很好干了他该干的事。我想可能是你搞错了,导致死锁了吧。

  回复  引用    

#6楼 [楼主] 2006-01-17 10:10 shootingstars      
To wuzq
不知道你是如何做的测试,能够把测试代码贴出来吗?

  回复  引用  查看    

#7楼 [楼主] 2006-01-17 10:37 shootingstars      
To world
SendMessageA发送的消息确实不进入消息循环,但是这个过程是在主线程的上下文中完成的,还是在开的线程中完成的?
呵呵,有空再研究研究,或许原理还是有问题。

  回复  引用  查看    

console不会是因为他没有消息循环的原因吧。猜想你的程序可能是创建一个线程之后就让它在console停在那里了对吧,这是正常的,但是在有窗口消息的程序中就不行了。
我是一个初学者,有VC高手希望能交个朋友。
我的E-MAIL:puma-ly@163.com

  回复  引用    

#9楼 2006-03-28 16:27 za [未注册用户]
非常感谢!!!,
  回复  引用    

#10楼 2006-06-18 20:10 mjk [未注册用户]
解决了我2天百思不得其解的问题, 谢谢.
  回复  引用    

#11楼 2006-11-27 09:21 cm [未注册用户]
谢谢!帮我解决了一个问题
  回复  引用    

#12楼 2006-11-27 09:21 cm [未注册用户]
谢谢!帮我解决了一个问题
  回复  引用    

#13楼 2006-11-27 09:21 cm [未注册用户]
谢谢!帮我解决了一个问题
  回复  引用    

直接把for(;;)去掉就可以了吧。那样while循环条件不成立时函数就返回了,WaitForSingleObject也就返回了。
  回复  引用    

SendMessage的目标窗口如果属于另一个线程,则会发生线程上下文切换,等待另一线程处理完成消息。为了防止另一线程当掉,导致SendMessage永远不能返回,我们可以调用SendMessageTimeout函数

 

  回复  引用    

#16楼 2007-07-19 16:32 IfI [未注册用户]
太感谢了,困扰我好几个礼拜的问题啊....

不过在WaitForSingleObject的第二个参数设置成一个数值也可以避免出问题,不过没有楼主的效果好~

  回复  引用    

我要在主线程中开启一个UI线程,该UI线程查找某种设备,所以主线程要阻塞,一直到UI线程结束,我该怎么办呢
  回复  引用    

#18楼 [楼主] 2007-10-08 13:29 shootingstars      
To zhcen
你的主线程不是一个UI线程吗?
我的建议是:在UI线程中等待某个事件发生一定使用MsgWaitForMultipleObjects,不要使用WaitForMultipleObjects。

  回复  引用  查看    

是你自己字线程本身代码有问题,不是WaitForSingleObject的错
for没办法退出,怎么WaitForSingleObject?

  回复  引用    

你好,看了你的代码后对我帮助很大,但同时也发现了个很奇怪的问题。
在debug版本下面正常运行
但如果在release版本下,你的等待那个函数
while(TRUE)
{
DWORD result ;
MSG msg ;
result = MsgWaitForMultipleObjects(1, &readThreadHandle,
FALSE, INFINITE, QS_ALLINPUT);

if (result == (WAIT_OBJECT_0))
{
break;
}
else
{
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
DispatchMessage(&msg);
}
}
好像就没起作用了。
我估计是不是函数的返回值有问题。。。不太清楚,希望你能帮忙看下,
谢谢!!

  回复  引用    

微软的文档写得清清楚楚啦,凡是创建窗口的线程必须谨慎使用该函数!
  回复  引用    

LZ看了你的文章后有些疑惑的,

1. 的线程代码中的 for(;;){
ReadInfoFromList();
InsertToCListCtrl();
}
好像没有必要要for(;;){}这一层吧,这样的话你的while(!bTerminate)就没有什么意义了,永远没法执行到吧,

2. result = MsgWaitForMultipleObjects(1, &readThreadHandle, FALSE, INFINITE, QS_ALLINPUT); 如果你用INFINITE永远等待不超时后面的代码在在等待的时间没有发生的情况下还能执行到吗?

  回复  引用    

#23楼 2008-03-25 19:22 梦书      
太感谢了!
  回复  引用  查看    

22楼白痴。
回答你
1,人家那是简写。难道楼主故意写个死循环在那么?

2,你根本就没看懂。人家说是有消息来也可以往下执行。知道什么是有消息么?

  回复  引用    

楼主搞错了。
CListCtrl 只能在主线程操作。
WaitForSingleObject 没问题。

  回复  引用    

WaitForSingleObject(threadHandle, INFINITE);中INFINITE改为0也可以返回的。

免责声明:文章转载自《在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Keepalived 进程无法关闭后台界面设计之表单设计规范参考下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Java多线程中static变量的使用

线程,是我们项目中绕不过的重点领域。提到线程,就常会听到线程安全的术语。那什么是线程安全呢?通俗点说,就是线程访问时不产生资源冲突。其实,这是一个有点难以定义的概念,不是很容易让人一听就懂的概念。“一个类可以被多个线程安全调用就是线程安全的”《Java并发编程实践》。     来说说静态变量、实例变量、局部变量在多线程下的安全问题吧!     (一)静态变...

Javascript:再论Javascript的单线程机制 之 DOM渲染时机

Javascript:再论Javascript的单线程机制 之 DOM渲染时机 背景 Javascript是单线程事件驱动的,所有能看到的Javascript代码都是在一个线程执行,定时器回调和AJAX回调会在适当的时刻插入队列等待Javascript线程调度执行,今天想测试一下DOM渲染的线程与时机,具体的问题是: 修改DOM会立即显示在UI中吗? 一个...

Java 多线程加锁的方式总结及对比(转载)

转自https://blog.csdn.net/u010842515/article/details/67634813 参考博文:http://www.cnblogs.com/handsomeye/p/5999362.html 一.Java多线程可以通过: 1. synchronized关键字 2. Java.util.concurrent包中的lock接...

Java 并发系列之十:java 并发框架(2个)

1.Fork/Join框架 2.Executor框架 3.ThreadPoolExecutor 4.ScheduledThreadPoolExecutor 5.FutureTask 6.txt 1 java并发框架 2 Fork/Join框架 3 定义 4 一个用于并行执行任务的框架,是一个把大任务分割成若干个小任务,最终汇总每...

网络通信框架Apache MINA

Apache MINA(Multipurpose Infrastructure for Network Applications) 是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络应用程序提供了非常便利的框架。当前发行的 MINA 版本支持基于 Java NIO 技术的TCP/UDP 应用程序开发、串口通讯程序。Mina 的应用层:一个...

多线程处理同一个List测试dome

package com.sysware.p2m.task.op.process; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; public class ThreadTese{ static cla...