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 调用)。结果,StreamThreadWorker正在等待FrameArrived完成,但由于线程正在等待完成而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 回答