S.l.e!ep.¢%

像打了激速一样,以四倍的速度运转,开心的工作
简单、开放、平等的公司文化;尊重个性、自由与个人价值;
posts - 1098, comments - 335, trackbacks - 0, articles - 1
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

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

线程函数:

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, 00, PM_REMOVE);
        DispatchMessage(
&msg); 
    }
 
}


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

Feedback

# re: 在主线程中慎用WaitForSingleObject (WaitForMultipleObjects) (转)  回复  更多评论   

2009-06-26 11:42 by hhy
呵呵,顶一个,少走弯路了 :)

# re: 在主线程中慎用WaitForSingleObject (WaitForMultipleObjects) (转)  回复  更多评论   

2009-12-02 10:11 by aaa
好文章要顶。

# re: 在主线程中慎用WaitForSingleObject (WaitForMultipleObjects) (转)  回复  更多评论   

2009-12-10 07:20 by Tiany
谢谢你的好文章! 我也为这个问题烦恼了2天了 碰巧来到你这里 哈!给解决了 以后会经常来看你的

# re: 在主线程中慎用WaitForSingleObject (WaitForMultipleObjects) (转)  回复  更多评论   

2010-03-27 01:31 by
我正遇到几乎一样的问题了,仍然没有解决。对你的观点有疑问。
我下面的代码和你说的几乎一样,但是每次都能正确执行。?????
我的qq:312763408


DWORD CTestClistCtrlDlg:: ThreadSendData (LPVOID lParam)
{

CTestClistCtrlDlg *p = (CTestClistCtrlDlg*)lParam;

CString strOut;
int i = 0;
g_bStop = false;


while (!g_bStop)
{

p->m_ctlMyTable.InsertItem(i,"1");
p->m_ctlMyTable.SetItemText(i,1,"haha");
Sleep(1);
}

TRACE("end \n");
return 0;

}
void CTestClistCtrlDlg::OnBtnStop()
{
// TODO: Add your control notification handler code here
g_bStop = true;
WaitForSingleObject (m_hThread, INFINITE);
}

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理