关闭表单时出现异常(线程+调用)

Posted

技术标签:

【中文标题】关闭表单时出现异常(线程+调用)【英文标题】:Exception when closing Form (thread + invoke) 【发布时间】:2013-11-06 08:23:54 【问题描述】:

我刚开始学习c#中的线程和方法调用,但遇到了一个我找不到解决方案的问题。

我制作了一个基本的 C# 表单程序,它通过启动一个线程并调用委托来不断更新和显示数字。

在 Form1_load 上启动新线程:

private void Form1_Load(object sender, EventArgs e)
  
        t = new System.Threading.Thread(DoThisAllTheTime);
        t.Start();
  

Public void DoThisAllTheTime(不断更新数字):

public void DoThisAllTheTime()
  
     while(true)
      
        if (!this.IsDisposed)
         
           number += 1;
           MethodInvoker yolo = delegate()  label1.Text = number.ToString(); ;
           this.Invoke(yolo);
         
      
  

现在,当我单击表单的 X 按钮时,出现以下异常:

'System.Windows.Forms.dll 中发生'System.ObjectDisposedException' 类型的未处理异常

无法更新已删除的对象'

虽然我确实检查了表单是否已处理。

编辑:我在解决问题的代码中添加了 catch (ObjectDisposedException ex)。 工作代码:

  public void DoThisAllTheTime()
  
     while(true)
      
         number += 1;

         try   
              MethodInvoker yolo = delegate()  label1.Text = number.ToString(); ;
              this.Invoke(yolo);
             
         catch (ObjectDisposedException ex)
             
              t.Abort();
             
      
 

【问题讨论】:

好吧,在计算 (!this.IsDisposed) 之后,但在调用 this.Invoke(yolo); 之前,表单被处理掉了。欢迎来到赛车世界。 我已经编辑了你的标题。请参阅“Should questions include “tags” in their titles?”,其中的共识是“不,他们不应该”。 @Joker_vD 我该如何解决这个问题?我认为检查会比方法调用更快。它也在 MSDN 上以这种方式使用。 (msdn.microsoft.com/en-us/library/…) 正如其他人已经说过这是一个种族问题,请参阅:***.com/questions/1874728/… @Bart 不要指望 MSDN 示例代码是正确的。通常情况下,它不是。 【参考方案1】:

您对this.IsDisposed 的电话总是过期的。您需要拦截表单关闭事件并明确停止线程。那么你就完全不用做IsDisposed 测试了。

有很多方法可以做到这一点。就个人而言,我会使用System.Threading.Tasks 命名空间,但如果你想继续使用System.Threading,你应该定义一个成员变量_updateThread,并在你的加载事件中启动它:

_updateThread = new System.Threading.Thread(DoThisAllTheTime);
_updateThread.Start();

那么在你的闭幕式上:

private void Form1_Closing(object sender, CancelEventArgs e)

    _stopCounting = true;
    _updateThread.Join();

最后,将IsDisposed 测试替换为检查新的_stopCounting 成员变量的值:

public void DoThisAllTheTime()

    MethodInvoker yolo = delegate()  label1.Text = number.ToString(); ;
    while(!_stopCounting)
    
        number += 1;
        this.Invoke(yolo);
    

【讨论】:

我尝试添加 't.abort();'到 Form1_closure,但这也无济于事。 @Bart:尝试设置一个标志,然后调用t.Join(); 等待线程识别它。 我在其中添加了 catch (ObjectDisposedException ex)。这解决了问题。我会更新我的问题。 @Bart:正如 oefe 所说,这太令人发指了! :D 由于Invoke正在阻塞等待主线程,如果在number += 1;行上执行Form1_Closing方法,这里就有死锁的可能。随着越来越多的工作代替这条线完成,僵局的机会就会增加。我通过使用BeginInvoke 而不是Invoke 在我的应用程序中修复了这个问题,因为BeginInvoke 不会阻止线程退出,因此Join 不会永远阻塞。【参考方案2】:

只需将此覆盖放在您的表单类中:

protected override void OnClosing(CancelEventArgs e) 
    t.Abort();
    base.OnClosing(e);

【讨论】:

+1 一个不错的解决方案。要获取更多信息:请参阅***.com/questions/1874728/… @Alireza 谢谢哥们。答案与我从问题中获得的初学者技能兼容。但真的谢谢。干杯 正常场景关闭不得包括对Thread.Abort()Application.Exit() 等的调用。我已经看到了一个由此引起的错误——由于Environment.Exit() spurios 而没有回滚事务在 OnClose() 事件处理程序中。【参考方案3】:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)

Thread.CurrentThread.Abort();

【讨论】:

以上是关于关闭表单时出现异常(线程+调用)的主要内容,如果未能解决你的问题,请参考以下文章

Android:当我使用 AsyncTask 时出现“调用线程必须是准备好的 Looper 线程”错误

尝试从 JSP 表单调用 servlet 时出现 404 错误

GWT:分派传入 RPC 调用时出现异常

从活动调用片段方法时出现空指针异常

调度传入 RPC 调用时出现异常

当我使用 curl 命令调用服务时出现异常“UT000004:getResponseChannel() 已被调用”