分类:
2008-10-13 16:30:55
除虫记之八(WM_QUIT和结束线程:1小时/1人)
公测的时候又发现一个问题,因为一个商务上问题,程序中去掉了一个模块(dll)的调用,打包公测后,发现程序在退出后而聊天进程没有退出,等待了很长时间也没有退出。
开发人员在调试的时候,已经在debug版本下重现了这个bug,跟踪代码出错部分的流程如下:
发送WM_QUIT消息给一个工作线程让其退出;
用WaitForSingleObject等待那个线程的句柄有信号;
如果有信号,就直接CloseHandle掉这个线程句柄;
如果超时没有信号,就直接用_endthreadex()杀死线程。
开发人员跟踪了好多次发现消息发送过去后线程并没有退出,每次都要超时进入强杀流程,但强杀调用确没有杀死线程,从thread里面还可以明确的看到这个线程在运行,于是就导致了进程没有退出!
跟踪了好几次都找不到问题所在,让我过去看看。
很明显,进程没有退出,就是因为这个线程没有退出的缘故。我一开始怀疑是不是线程没有收到这个消息,于是在处理消息的地方加上断点,ft,结果频频进入断点,程序一下子就失去了反应,连VC都没有响应了,不得已在进程管理器中杀死,按说在调试状态,进程管理器是不让杀的,但不知为何偏偏杀死了,且不管他。把断点去掉,在Post线程消息前加断点,然后再在线程的消息处理中加断点。运行,Post线程消息成功,F5运行,靠,竟然没有走到线程消息处理的断点里面。线程没有收到消息????
运行多次,都是同一个现象。
因为只是一个杀死线程的操作,想让线程死还不容易啊,于是建议开发人员用TerminateThread()强杀线程,开发人员开始不理解,说线程是用_beginthreadex启动的,应该用_endthreadex杀死。我说就按我说的做,呵呵,线程如期被我们干掉了,进程退出了。
趁此机会,又给开发人员讲解了一番C运行库函数和Win32API的优劣比较。
让他们编译release版后送给测试部去验证,我又开始仔细那个线程处理消息的流程,我打了好多调试语句,怎么都发现没有收到退出的消息。晕啊。
忽然,注意到了WM_QUIT消息,哈,想起来了,自己曾经又一次就是用这个消息让线程退出,但没有成功,后来改程自定义的消息就可以了,立刻动手改成WM_USER+113,哈,收到了退出的消息,线程如期自动退出了!
哈哈,立刻又第n次的简单看了看WM_QUIT消息,然后告诉开发人员说WM_QUIT消息只能由应用程序主线程处理做程序退出。
我犯了一个大错误!
刚转了一圈回来,开发人员小声的说不是WM_QUIT消息的问题,被我听到了。
立刻追问,原来开发人员第一次的认真看了看WM_QUIT消息的MSDN文档,发现并不是线程不能处理WM_QUIT消息,而是线程中用GetMessage接收消息,而接收到这个消息后GetMessage返回0,就是这个0,被程序用if给if掉了!
我犯了一个大错误!我以为我对API已经很熟悉了,但看来远远不是!远远不是!
教训:尽可能用Win32的API,尽量的少用 c 运行库函数。WM_QUIT消息可以被任何线程处理。