关闭多线程应用程序时ObjectDisposed

时间:2012-12-18 12:34:30

标签: c# multithreading invoke aforge objectdisposedexception

  

可能重复:
  How to stop BackgroundWorker on Form’s Closing event?

**关于可能的重复 - BackgroundWorker方法不适用于此。

以下是我尝试使用AForge库从IP摄像机接收视频。

每个视频流应该在单独的线程中运行,在新帧到达时通知UI线程。事件处理程序在同一个线程中执行,引发它,所以我需要使用Invoke。

所有操作都顺利进行,直到我想停止申请。标有'>>>'的行抛出ObjectDisposed异常,因此我的应用程序不会像运行一样顺利结束。

我知道问题是理解多线程,因为它无法看到真正的问题。有人可以解释一下这里发生了什么吗?

Form1.cs

public void generic_NewFrame(object sender, NewFrameEventArgs e)
{
  ...
  if (pictureBox1.InvokeRequired)
  {                            
>>>   pictureBox1.Invoke(new MethodInvoker(delegate()
                         {                                                       
                           pictureBox1.BackgroundImage = (Image)buf;
                         }));
  }
  else
  {
    pictureBox1.BackgroundImage = (Image)buf;
  }
  ...
}

尽可能短,Camera class:

Camera.cs
//Camera thread loop
private void WorkerThread()
{
  while (!stopEvent.WaitOne(0, false))
  {
   ...
     if (!stopEvent.WaitOne(0, false))
     {
       // notify UI thread
       OnNewFrame(new NewFrameEventArgs(Last_frame));
   ...
  }  
}

override public void Play()
{
  stopEvent = new ManualResetEvent(false);

  thread = new Thread(new ThreadStart(WorkerThread));
  thread.Start();
}

override public void Stop()
{
  if (thread != null)
  {
    stopEvent.Set();
  }
}

2 个答案:

答案 0 :(得分:1)

我认为问题出在以下方面:图书馆在关闭您的表单后调用您的回调(generic_NewFrame。 你可以用几种不同的方式解决它。

首先,如果您的表单已经处理,您可以跳过回调方法:

public void generic_NewFrame(object sender, NewFrameEventArgs e)
{
  // Lets skip this callback if our form already closed
  **if (this.IsDisposed) return;**

  ...
  if (pictureBox1.InvokeRequired)
  {                            
>>>   pictureBox1.Invoke(new MethodInvoker(delegate()
                         {                                                       
                           pictureBox1.BackgroundImage = (Image)buf;
                         }));
  }
  else
  {
    pictureBox1.BackgroundImage = (Image)buf;
  }
  ...
}

另一种方法是等待,不要关闭你的表格直到你的图书馆仍在工作并等待FormClosingFormClosed事件处理程序:

private void FormClosingEventHandler(object sender, CancelEventArgs e)
{
  // Waiting till your worker thread finishes
   _thread.Join();
}

或者你可以在你的停止方法中等待:

override public void Stop()
{
  if (thread != null)
  {
    stopEvent.Set();
    thread.Join();
  }
}

答案 1 :(得分:0)

为了避免造成这种情况的竞争条件,您可以执行以下操作:

pictureBox1.Invoke(new MethodInvoker(delegate()
                     {                             
                       if (!pictureBox1.IsDisposed) 
                       {                      
                           pictureBox1.BackgroundImage = (Image)buf;
                       }
                     }));

在UI线程上检查IsDisposed是很重要的,即在调用的委托内部。