【发布时间】:2013-02-18 23:00:36
【问题描述】:
我有一个表单负责创建和设置一个对象的实例,然后告诉该对象去做它的工作。这个过程很长,所以表单上有一个区域显示状态消息,让用户知道正在发生的事情。使用 setMessage(string msg) 函数设置消息。为了让表单保持对事件的响应,我为要运行的对象创建了一个新线程,并将 setMessage 函数作为委托传递给它,以允许对象在表单上设置状态消息。这部分工作正常。主窗体是响应式的,发布到其 setMessage 函数的消息按预期显示。
因为这个过程很长,并且由许多步骤组成,所以我想让用户在它完成之前终止它。为此,我创建了一个名为 _stopRequested 的 volatile bool 和一个名为 shouldStop() 的函数,该函数返回其值。这也作为委托给对象。对象可以通过定期检查 shouldStop() 来判断它是否应该终止,如果为真,则正常关闭。
最后,Windows 控件不是线程安全的,因此如果创建控件的线程以外的线程试图操作它,编译器会报错。因此,setMessage 函数被包装在一个 if 语句中,该语句对此进行测试,如果它是从工作线程调用的,则使用父线程调用该函数(有关说明,请参见 http://msdn.microsoft.com/en-us/library/ms171728(v=vs.80).aspx)。
当用户请求关闭时,就会出现问题。主窗体将 _stopRequested 设置为 true,然后在关闭应用程序之前等待子线程完成。它通过执行 _child.Join() 来做到这一点。现在父线程(运行表单的线程)处于 Join 状态,不能做任何事情。子线程(运行长进程)检测到停止标志并尝试关闭,但在此之前,它通过调用它的 setMessage 委托来发布状态消息。该委托指向主窗体,它表明设置消息的线程(子)与创建控件(父)并在父线程中调用函数的线程不同。当然,父线程处于 Join 状态,并且在子线程终止之前不会在文本框上设置文本。子线程不会终止,因为它正在等待它调用的委托返回。瞬间死锁。
我找到了发出线程终止信号的示例,我还找到了子线程向父线程发送消息的示例,但是我找不到任何同时发生这两种事情的示例。有人可以给我一些关于如何避免这种僵局的指示吗?具体来说,我希望表单在关闭应用程序之前等到子线程终止,但在它等待时仍然可以工作。
提前感谢您的建议。
【问题讨论】:
-
GUI 事件处理程序中的 Join() - 经典的 Join 生成的死锁。第一种尝试方法 - 如果您只是注释掉 Join() 会发生什么?
-
第二种方法 - 发布另一个“ThreadActionCompleted”委托作为线程的最后一行,(当然,转储加入)。
-
..然后试着忘记你曾经听说过 Join() :)
-
..不要再等待 GUI 事件处理程序中的任何内容 :)
标签: multithreading delegates deadlock