2012-06-04 80 views
1

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

回答

2

可能發生的情況是:單擊Stop,這將在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 
} 
+0

這似乎是合乎邏輯的。我會試試看。如果線程本身終止,爲什麼需要'Abort()'? – Itsik

+0

如果'Join'沒有及時完成(在我的例子中是3秒),則中止強制停止。如果加入電話確實成功了,放棄不起作用 – stijn

+0

謝謝...現在這個工作:) – Itsik