——Windows GUI程序中使用线程的心得体会
①避免在工作者线程中使用SendMessage,改用PostMessage比较好。
原因是这样的,以一个普通程序退出为例,我们经常会使用以下方式构建退出逻辑:
|
主线程正在消息处理函数 |
工作者线程正在处理任务 |
|
void OnDestroy(){//WM_DESTROY |
void DoWork(){ |
如上所示,只要主线程开始处理WM_DESTROY消息后,只有等到OnDestroy返回,主线程才会处理下一个Windows消息。一旦OnDestroy函数开始执行且还没有返回,DoWork中发出的WM_GETTEXT消息就不会被主线程处理,使用SendMessage后工作者线程就会等待主线程处理WM_GETTEXT进入休眠,注意这种休眠无法使用ResumeThread唤醒(即使唤醒只要主线程没有处理WM_GETTEXT消息也会继续睡过去)。而这时OnDestroy函数正在用WaitForSingleObject等待DoWork检测m_hStop信号退出线程,所以两者互相等待都进入了休眠,这样就产生了死锁。
很多朋友一定会说,那就把OnDestroy里WaitForSingleObject去掉直接往后执行不就没有死锁了么?死锁是没有了,由于OnDestroy函数的主要职责就是负责释放资源,接下来它一定会调用类似CWnd::OnDestroy()函数来销毁窗口资源,这样一来DoWork里就很有可能因为访问界面资源而崩溃。
所以,②应该避免在工作者线程中直接访问界面资源,包括不要使用GetWindowsText等函数。可以把要显示到界面上的数据,放进一个自己构建的队列中,然后使用PostMessage发出特定的消息或者用户自定义的消息,由消息处理函数去完成。
③如果必须在线程里访问界面资源怎么办?可以使用类似MFC中的界面线程。
下面是我在工作者线程里直接访问界面资源的方法,利用消息泵:
|
工作者线程正在处理任务 |
|
void DoWork(){ |
上面也许不是解决退出死锁的万能方法,只是我的一点心得,希望大家有更好的办法也贴上来。
本文分享了在Windows GUI程序中使用线程的经验教训,包括避免在工作者线程中使用SendMessage,推荐使用PostMessage;避免直接访问界面资源,建议通过消息队列更新UI;并提供了如何在线程中正确访问界面资源的方法。

2011

被折叠的 条评论
为什么被折叠?



