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

Joh*_*ohn 5 c# multithreading exception

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

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

在Form1_load上启动新线程:

private void Form1_Load(object sender, EventArgs e)
  {
        t = new System.Threading.Thread(DoThisAllTheTime);
        t.Start();
  }
Run Code Online (Sandbox Code Playgroud)

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

public void DoThisAllTheTime()
  {
     while(true)
      {
        if (!this.IsDisposed)
         {
           number += 1;
           MethodInvoker yolo = delegate() { label1.Text = number.ToString(); };
           this.Invoke(yolo);
         }
      }
  }
Run Code Online (Sandbox Code Playgroud)

现在当我单击表单的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();
             }
      }
 }
Run Code Online (Sandbox Code Playgroud)

Rob*_*don 4

您的呼叫this.IsDisposed始终已过时。您需要拦截表单关闭事件并显式停止线程。IsDisposed那么你就根本不需要做那个测试了。

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

_updateThread = new System.Threading.Thread(DoThisAllTheTime);
_updateThread.Start();
Run Code Online (Sandbox Code Playgroud)

然后在闭幕活动中:

private void Form1_Closing(object sender, CancelEventArgs e)
{
    _stopCounting = true;
    _updateThread.Join();
}
Run Code Online (Sandbox Code Playgroud)

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

public void DoThisAllTheTime()
{
    MethodInvoker yolo = delegate() { label1.Text = number.ToString(); };
    while(!_stopCounting)
    {
        number += 1;
        this.BeginInvoke(yolo);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 由于“Invoke”会阻塞等待主线程,因此如果在“number += 1;”行执行“Form1_Closing”方法,则可能会出现死锁。随着越来越多的工作取代该线,出现僵局的可能性就会增加。我通过使用“BeginInvoke”而不是“Invoke”在我的应用程序中修复了这个问题,因为“BeginInvoke”不会阻止线程退出,因此“Join”不会永远阻塞。 (2认同)