1

可能重复:
如何在窗体的关闭事件中停止 BackgroundWorker?

**关于可能的重复 - 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 类:

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();
  }
}
4

2 回答 2

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();
  }
}
于 2012-12-18T12:43:18.600 回答
0

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

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

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

于 2012-12-18T13:36:52.560 回答