1

重複の可能性:
フォームの Closing イベントで 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;
  }
  ...
}

もう1つのアプローチは、ライブラリがまだ機能するまでフォームを閉じずに待機しFormClosingFormClosedイベントハンドラーで待機することです。

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

または、stopメソッドで待機することもできます。

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

IsDisposedUI スレッド、つまり呼び出されたデリゲート内でチェックされることが重要です。

于 2012-12-18T13:36:52.560 に答える