事件后线程未完成

Posted

技术标签:

【中文标题】事件后线程未完成【英文标题】:Thread not finishing after Event 【发布时间】:2013-12-10 19:26:03 【问题描述】:

看看这个简单的类:

delegate void Log(String message);
class A 
  public Log log;

  ...

  public void test() 
    // Empty
  


现在我正在从主 GUI 线程创建和启动一个线程并检查它是否结束。

A a = new A();
a.log += Log;

Thread t = new Thread(new ThreadStart(a.test));
t.Start();

while(true) 
  System.Threading.Thread.Sleep(200);
  Console.WriteLine(t.IsAlive);


上面的代码一切正常:

true
true
....
false
false
false
...

现在当我将test 方法的代码更改为

public void test() 
  log("Test");

GUI 类中的Log 方法如下所示:

private void Log(String message)
        
            if (this.tb_log.InvokeRequired)
            
                this.tb_log.Invoke((MethodInvoker)delegate()
                
                    Log(message);
                );
            
            else
            
                // do something with the textbox in the GUI
            
        

现在,虽然函数终止了,但我得到了以下控制台日志:

true
true
true
true
true
true
...

线程永远不会终止。你能解释一下吗?

【问题讨论】:

你能检查一下当你改用BeginInvoke时问题是否仍然存在吗? 显而易见的建议是它永远递归地调用自己。 我不确定,只是一个假设 - 您正在尝试调用处于无限 while 循环中的 GUI 线程上的方法。所以你的 this.tb_log.Invoke 调用永远不会结束 @Jeremy:不,该方法正在正确完成。当我添加 Console.Write("abc");在 log("Test") 之后,我在控制台中得到了 "abc"。 @ChrisK:谢谢,BeginInvoke 工作正常! 【参考方案1】:

假设您的 while 循环发生在 GUI 线程上,您永远不会放弃对窗口的控制(因为您处于循环中)。您还应该发现您的 Invoke 永远不会返回。 (它通过在窗口的消息队列中放置一条消息来要求主线程做某事,但是你的主线程很忙,所以它永远不会使消息出队)

如果这只是测试代码,您可以改用 BeingInvoke,但实际上,您不应该在 UI 线程的后台线程上处于休眠状态并检查活动状态。

相反,让后台线程在完成时通过调用委托通知您的窗口,或者(更好)使用 BackgroundWorker (Winforms) 或 Task,使用 .ContinueWith() 调用来通知您的窗口已完成。

【讨论】:

以上是关于事件后线程未完成的主要内容,如果未能解决你的问题,请参考以下文章

保存在后台线程未完成

在 Loaded 事件中未完成渲染

取消所有未完成的 QTimer 事件

jquery是怎么实现:页面加载完毕,而图片未加载完成时,触发的事件?

jquery是怎么实现:页面加载完毕,而图片未加载完成时,触发的事件?

input输入中文未完成时触发change事件