戒赌吧 修空姐:在主线程中慎用WaitForSingleObject (WaitForMultipleOb...

来源:百度文库 编辑:中财网 时间:2024/04/28 17:35:20
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)

下面的代码我调试了将近一个星期,你能够看出什么地方出了问题吗?

线程函数:

DWORD WINAPI ThreadProc(
    while(!bTerminate)
    {
        // 从一个链表中读取信息并且插入到CListCtrl中
        // CListCtrl的句柄是通过线程参数传递进来的
        for(;;)
       {
           ReadInfoFromList();
           InsertToCListCtrl();
        }
    }
}
主线程中使用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用下面的代码替换:
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); 
    } 
}


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

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

评论

#1楼  2004-09-17 11:38 HXY [未注册用户]
谢谢你的文章!
  回复  引用    
#2楼  2004-12-10 11:00 Jeff [未注册用户] 太强了,解决了困扰我一整天的问题!!!
  回复  引用    
#3楼  2005-02-27 16:06 world [未注册用户]
作者你好,

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


  回复  引用    
#4楼  2005-11-19 02:09 msctor [未注册用户] 看了你的文章后,问题解决,非常感谢。
  回复  引用    
#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发送的消息确实不进入消息循环,但是这个过程是在主线程的上下文中完成的,还是在开的线程中完成的?
呵呵,有空再研究研究,或许原理还是有问题。
  回复  引用  查看    
#8楼  2006-01-18 16:32 蠕虫 [未注册用户] 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 [未注册用户] 谢谢!帮我解决了一个问题
  回复  引用    
#14楼  2006-12-03 01:12 Stzpz [未注册用户] 直接把for(;;)去掉就可以了吧。那样while循环条件不成立时函数就返回了,WaitForSingleObject也就返回了。
  回复  引用    
#15楼  2007-01-25 11:15 aGAric [未注册用户] SendMessage的目标窗口如果属于另一个线程,则会发生线程上下文切换,等待另一线程处理完成消息。为了防止另一线程当掉,导致SendMessage永远不能返回,我们可以调用SendMessageTimeout函数

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

不过在WaitForSingleObject的第二个参数设置成一个数值也可以避免出问题,不过没有楼主的效果好~
  回复  引用    
#17楼  2007-10-06 19:25 zhcen [未注册用户] 我要在主线程中开启一个UI线程,该UI线程查找某种设备,所以主线程要阻塞,一直到UI线程结束,我该怎么办呢
  回复  引用    
#18楼 [楼主] 2007-10-08 13:29 shootingstars       To zhcen
你的主线程不是一个UI线程吗?
我的建议是:在UI线程中等待某个事件发生一定使用MsgWaitForMultipleObjects,不要使用WaitForMultipleObjects。
  回复  引用  查看    
#19楼  2007-12-01 15:00 rocketma [未注册用户] 是你自己字线程本身代码有问题,不是WaitForSingleObject的错
for没办法退出,怎么WaitForSingleObject?
  回复  引用    
#20楼  2007-12-17 17:49 03060212 [未注册用户] 你好,看了你的代码后对我帮助很大,但同时也发现了个很奇怪的问题。
在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);
}
}
好像就没起作用了。
我估计是不是函数的返回值有问题。。。不太清楚,希望你能帮忙看下,
谢谢!!

  回复  引用    
#21楼  2007-12-25 18:35 Phrea [未注册用户] 微软的文档写得清清楚楚啦,凡是创建窗口的线程必须谨慎使用该函数!
  回复  引用    
#22楼  2008-02-13 15:56 joininthefun [未注册用户] LZ看了你的文章后有些疑惑的,

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

2. result = MsgWaitForMultipleObjects(1, &readThreadHandle, FALSE, INFINITE, QS_ALLINPUT); 如果你用INFINITE永远等待不超时后面的代码在在等待的时间没有发生的情况下还能执行到吗?
  回复  引用    
#23楼  2008-03-25 19:22 梦书       太感谢了!
  回复  引用  查看    
#24楼  2008-06-03 11:15 生锈的螺丝 [未注册用户] 22楼白痴。
回答你
1,人家那是简写。难道楼主故意写个死循环在那么?

2,你根本就没看懂。人家说是有消息来也可以往下执行。知道什么是有消息么?
  回复  引用    
#25楼  2008-07-24 12:38 fvvdv [未注册用户] 楼主搞错了。
CListCtrl 只能在主线程操作。
WaitForSingleObject 没问题。
  回复  引用    
#26楼  2008-11-10 09:47 gradylau [未注册用户] WaitForSingleObject(threadHandle, INFINITE);中INFINITE改为0也可以返回的。

主线程 创建失败 主线程“创建文件失败”? 主线程 网连接失败 主线程 是什莫东西啊 胸部慎用?? the hell当“究竟”讲时是不是也不礼貌?日常口语中是否要慎用? 开ie弹主线程框 幻想三国志2 中 说 夏侯翎不放心杜安 跟着杜安了 然后主线任务 让去找他们俩 他们俩在哪? 慎用的意思 有线如何装宽带?是否只能装在主线上 请你在家中随机选取10种药物,其中有哪些注明“孕妇慎用”或“孕妇禁用”的字样? 用delete命令删除记录为什么叫做逻辑删除,而使用pack或在zap命令为什么一定要慎用。 有谁知道怎么在一个线程里对主线程的窗口用DX9贴图,且保证要在其他的图程上1面??小弟谢了 一开网页就提示:主线程 创建文件失败 哪几集含柯南主线 为什么热饮要慎用吸管? 《完美世界》中,主线任务“矿场之乱”要杀的小boss是什么? 急求绝代双骄3主线任务中酒母的具体位置 三国演义中蜀并为统一天下。可为何叙事已蜀为主线。 漕宝路主线高架(A5-中环线)+地面铺道什么时候开工? 在我国,电话主线普及率中的电话主线指的是什么?人口指的是什么人口(常驻还是含流动)? 《地牢围攻2》中文版 主线任务 阿苏奈地窖在地图的位置 魏蜀吴三国争雄,虽然魏晋统一天下,却为何在叙事时以”蜀”为主线? 在仙侣奇缘2里的主线任务里遇到麻烦!请高手帮忙