工作线程界面输出时防止死锁的讨论

phisherr 2008-11-20 01:31:43
工作线程界面输出时防止死锁的讨论

背景:
这是一种很常见的情况,工作线程有一些或多或少的信息需要反映在界面上,比如在进度条上反映进度,在列表中显示并不断的刷新结果等等。这类操作本质上是向控件发消息sendmessage()。


问题:
如果主线程需要让工作线程停下来,或者也需要操作同一个控件的话,这就产生了一个同步问题。分两种情况
1、 主线程等待工作线程停止,如果这时工作线程向控件发消息(sendmessage),两个线程就会死锁;
2、 主线程和工作线程都需要操作控件,这两个线程必须互斥的操作这个控件,否则可能引起控件状态的不一致。如果简单的用临界区来互斥也可能会发生死锁。
(注意!!!这里的“操作”指的是一系列相互关联的操作,比如对列表进行多个项的更新,排序等等。单个的操作不在讨论之列,消息机制可以保证互斥)


一般的解决方案:
1、对于停止工作线程的情况:设置一个标志量,主线程在进入等待前先设置这个标志为true,工作线程在进行界面操作前先判断这个标志,如果标志为true就不对界面进行操作。
2、对于互斥操作控件的情况:设置一个标志,在线程A进行控件操作前设置为true,结束一系列的操作后设置为false;在另外一线程B中如果要操作控件就判断这边的标志,如果为true就进行等待,等待时使用 :PeekMessage() ::TranslateMessage); ::DispatchMessage();
来防止死锁。直到标志为false才进行操作。当然线程B在操作前后也要设置自己的标志量。


我提的问题:
以上的解决方法在实际运行中似乎没有出现过问题,但是根本经不起严格的分析。
依靠标志量的方法是不可靠的。对于1再密集的判断都不能保证:判断语句之后,sendmessage语句之前主线程不陷入等待。对于2不能保证线程B在设置自己的标志前,线程A判断B的标志为false从而两个线程对控件进行的复杂操作“混杂”起来。
这些标志会使程序变得复杂而不能真正的解决问题。

大家都来说说你们用什么方法解决这个问题呢,最好是简单又可靠
...全文
263 8 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
phisherr 2008-11-30
  • 打赏
  • 举报
回复
谢谢各位
nieoding 2008-11-21
  • 打赏
  • 举报
回复
尽量不要SendMessage呢,用postmessage+WaitForSignalObject
paerxiushi 2008-11-20
  • 打赏
  • 举报
回复
对于第一问题,主线程如果含有消息循环,就不应该去等待工作线程完成任务,因为长时间的等待会导致界面无法响应用户的操作。如果是因为特殊原因必须在UI线程中等待,请使用MsgWaitForMultipleObjects方法,这个方法允许你即能等待消息,又能等待事件信号。你需要设置函数超时时间,并且只有要一个事件或消息发送过来就让函数返回。这个函数需要在窗体过程接受到某个消息之前调用

对于第二问题,如果你的代码在WaitForSingleObject与ReleaseMutex之间发生的异常,一个使用互斥的线程会因为运行不到ReleaseMutex而让别的线程永久等待,造成死锁。这时方便的方法,就将互斥封装在一个类里面,将互斥的创建与释放工作分别让构造与析构函数完成。这样,即使发生了异常,因为类对象一定能释放,所以互斥也有机会释放掉。
whatabig 2008-11-20
  • 打赏
  • 举报
回复
这是一种很常见的情况,工作线程有一些或多或少的信息需要反映在界面上,比如在进度条上反映进度,在列表中显示并不断的刷新结果等等。这类操作本质上是向控件发消息sendmessage()。
===============================
in the first place, your framework has big problem.

for workerthread, since it usaually is an infinite loop, you MUST NOT have access to any of window handle for UI.

用一个队列保存介面更新请求,主线程定时检查这个队列
============================================
this solution is good,
-mainthread MUST have access to window handle.
-mainthread MUST have a kind of message communication with workerthread, depending on your requirements

in other words, mainthread controls everything, init, start, stop, resume, uninit,etc..
chenyu2202863 2008-11-20
  • 打赏
  • 举报
回复
索死的很大原因是同时等待窗口句柄造成的,所以在更新UI的动作一定是放在主线程中进行,工作线程发送消息来更新就可以,而且是用Post出去
aa3000 2008-11-20
  • 打赏
  • 举报
回复
蒋老大已经正解
蒋晟 2008-11-20
  • 打赏
  • 举报
回复
用一个队列保存介面更新请求,主线程定时检查这个队列
cnzdgs 2008-11-20
  • 打赏
  • 举报
回复
工作线程通过SendMessage发消息,让主线程来做各种处理;主线程利用事件控制工作线程;如果主线程需要等待工作线程,不要无限等待,在等待过程中要继续处理消息。

15,473

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧