I have a c++/cli wrapper class which grabs frames from a camera and sends them as events.
A WPF test application Starts the camera, and updates the images.
When I click Stop, it usually ends in a deadlock, on m->streamThread->Join(). I’m suspecting the problem has to do with the frame handling event in the WPF, rather than the wrapper code.
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);
}
}
likely what happens is: you click Stop, this gets handled in the WPF ui dispatcher thread. So the
Joincall is in the ui dispatcher thread. However this same thread is also responsible for drawing the frames (the invoked call to UpdateImage). As a result, theStreamThreadWorkeris waiting onFrameArrivedto finish, but that cannot finish because the thread is waiting forStopto finish. There’s your deadlock.So in order to get the
StreamThreadWorkerto finish, it must not be blocked byStop. An easy way to achive this is to stop the thread from within another thread: