1

カメラからフレームを取得してイベントとして送信する c++/cli ラッパー クラスがあります。

WPF テスト アプリケーション カメラを起動し、画像を更新します。をクリックするStopと、通常はデッドロックで終了しm->streamThread->Join()ます。問題は、ラッパー コードではなく、WPF のフレーム処理イベントに関係していると思われます。

namespace WpfTestApp
{
    public partial class Window1 : Window
    {

    private void OnFrameArrived(object sender, EventArgs e)
    {
        Action a = delegate 
        {
            // this uses Imaging.CreateBitmapSourceFromMemorySection
            // to copy the frame data to the image memory

            m_colorImage.UpdateImage(e.Image);
        };

        Dispatcher.Invoke(a);
    }

    private void startBtn_Click(object sender, RoutedEventArgs e)
    {
        m_camera.FrameArrived += m_frameHandler;
        m_camera.Start();
    }

    private void Stop()
    {
        m_camera.FrameArrived -= m_frameHandler;
        m_camera.Stop();
    }
    }
}

// Camera.h
public ref class Camera
{
public:
    delegate void FrameArrivedHandler(Object^ sender, DGEventArgs^ e);        
    event FrameArrivedHandler^ FrameArrived;

    void Start();
    void Stop();

 private:
    void StreamThreadWorker();
    Thread^ m_streamThread;
    bool m_isStreaming;
 }

 // Camera.cpp
void Camera::Start() 
{
    if (m_isStreaming)
        return;

    m_isStreaming = true;

    m_streamThread = gcnew Thread(gcnew ThreadStart(this, &Camera::StreamThreadWorker));
    m_streamThread->Start();
}

void Camera::Stop()
{
    if (!m_isStreaming)
        return;

    m_isStreaming = false;

    m_streamThread->Join(); // stuck here
}

void Camera::StreamThreadWorker()
{
    EventArgs^ eventArgs = gcnew EventArgs();

    while (m_isStreaming)
    {
        eventArgs->Image = Camera->GetImage();

        FrameArrived(this, eventArgs);
    }
}
4

1 に答える 1

2

おそらく何が起こるか: [停止] をクリックすると、これは WPF ui ディスパッチャー スレッドで処理されます。したがって、Join呼び出しは ui ディスパッチャ スレッドにあります。ただし、この同じスレッドがフレームの描画も担当します (UpdateImage への呼び出された呼び出し)。その結果、StreamThreadWorkerFrameArrived終了を待っていますが、スレッドが終了を待っているため、終了できませんStop。あなたのデッドロックがあります。

したがって、StreamThreadWorkerを終了させるためには、 によってブロックされてはなりませんStop。これを実現する簡単な方法は、別のスレッド内からスレッドを停止することです。

void Camera::Stop()
{
  ...

  gcnew Thread( gcnew ThreadStart( this, &Camera::DoStopThread ) )->Start();
}

void Camera::DoStopThread()
{
  if( !m_streamThread.Join( 3000 ) )
    HandleThreadDidNotStopInTimeError(); //notify listeners there's a serious problem
  m_streamThread.Abort();
  m_streamThread = null;
  RaiseThreadStoppedEvent(); //notify listeners that the thread stopped
}
于 2012-06-04T10:01:39.157 に答える