下面的代码我调试了将近一个星期,你能够看出什么地方出了问题吗?
线程函数:
DWORD WINAPI ThreadProc(
while(!bTerminate)
{
// 从一个链表中读取信息并且插入到CListCtrl中
// CListCtrl的句柄是通过线程参数传递进来的
for(;;)
{
ReadInfoFromList();
InsertToCListCtrl();
}
}
}
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);
}
}
{
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一类函数,而必须使用上述的方案。
评论
谢谢你的文章!
回复 引用
回复 引用
作者你好,
消息循环只负责获取消息队列中的消息 ,
SendMessageA的消息并不进入消息队列
回复 引用
回复 引用
并没有出现你说的事情,线程依然很好干了他该干的事。我想可能是你搞错了,导致死锁了吧。
回复 引用
不知道你是如何做的测试,能够把测试代码贴出来吗?
回复 引用 查看
SendMessageA发送的消息确实不进入消息循环,但是这个过程是在主线程的上下文中完成的,还是在开的线程中完成的?
呵呵,有空再研究研究,或许原理还是有问题。
回复 引用 查看
我是一个初学者,有VC高手希望能交个朋友。
我的E-MAIL:puma-ly@163.com
回复 引用
回复 引用
回复 引用
回复 引用
回复 引用
回复 引用
回复 引用
回复 引用
不过在WaitForSingleObject的第二个参数设置成一个数值也可以避免出问题,不过没有楼主的效果好~
回复 引用
回复 引用
你的主线程不是一个UI线程吗?
我的建议是:在UI线程中等待某个事件发生一定使用MsgWaitForMultipleObjects,不要使用WaitForMultipleObjects。
回复 引用 查看
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);
}
}
好像就没起作用了。
我估计是不是函数的返回值有问题。。。不太清楚,希望你能帮忙看下,
谢谢!!
回复 引用
回复 引用
1. 的线程代码中的 for(;;){
ReadInfoFromList();
InsertToCListCtrl();
}
好像没有必要要for(;;){}这一层吧,这样的话你的while(!bTerminate)就没有什么意义了,永远没法执行到吧,
2. result = MsgWaitForMultipleObjects(1, &readThreadHandle, FALSE, INFINITE, QS_ALLINPUT); 如果你用INFINITE永远等待不超时后面的代码在在等待的时间没有发生的情况下还能执行到吗?
回复 引用
回复 引用 查看
回答你
1,人家那是简写。难道楼主故意写个死循环在那么?
2,你根本就没看懂。人家说是有消息来也可以往下执行。知道什么是有消息么?
回复 引用
CListCtrl 只能在主线程操作。
WaitForSingleObject 没问题。
回复 引用