C ++ / CLI Wrapper中的死锁

时间:2012-06-04 08:28:46

标签: c# wpf c++-cli

我有一个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);
    }
}

1 个答案:

答案 0 :(得分: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
}