我正在运行一个线程,该线程从相机获取图像,将其保存,并更新pictureBox以显示该位图。当我想退出应用程序时,将布尔exitApplication
设置为true,但它从未在join()
调用中返回。
public void GrabThread()
{
Bitmap copyBmp;
while (!exitApplication)
{
mImage = m_camera.GrabImage();
SaveImage();
copyBmp = (Bitmap)mImage.bmp.Clone();
if (pictureBox1.InvokeRequired)
{
pictureBox1.Invoke(new MethodInvoker(
delegate ()
{
pictureBox1.Image = copyBmp;
}));
}
else
{
pictureBox1.Image = copyBmp;
}
m_camera.ReleaseImage();
}
}
我的退出代码:
exitApplication = true;
threadGrab.Join();
m_camera.Stop();
Close();
当我从“调试”菜单调用“全部中断”时,线程挂起
pictureBox1.Invoke(new MethodInvoker(
delegate ()
{
pictureBox1.Image = copyBmp;
}));
为什么?我该如何预防呢?目前,我必须在线程上调用Abort()退出它。
答案 0 :(得分:1)
此代码陷入僵局,因为pictureBox1.Invoke
试图在UI线程中执行代码。不过,该线程被调用threadGrab.Join();
可以使用async/await
进行修复。 await
等待已经执行的异步任务,而不会阻塞Join()
的工作方式。完成后,将在原始同步上下文中恢复执行。在WinForms或WPF应用程序中,这意味着将在UI线程上恢复执行。
我假设唯一需要在后台运行的是m_camera.GrabImage();
。在这种情况下,代码可能看起来像这样:
public async void Button1_Click(object sender, EventArgs args)
{
await Task.Run(()=>m_camera.GrabImage();
//Back in the UI thread
SaveImage();
var copyBmp = (Bitmap)mImage.bmp.Clone();
pictureBox1.Image = copyBmp;
m_camera.ReleaseImage();
}
Task.Run
将在线程池线程中执行m_camera.GrabImage()
。 await
将等待完成而不会阻塞UI线程。完成后,将在UI线程中恢复执行,这意味着不需要Invoke
。
这也可以循环运行:
public async void Capture_Click(object sender, EventArgs args)
{
while(someCondition)
{
await Task.Run(()=>m_camera.GrabImage();
SaveImage();
var copyBmp = (Bitmap)mImage.bmp.Clone();
pictureBox1.Image = copyBmp;
m_camera.ReleaseImage();
}
}
答案 1 :(得分:0)
这可能不是正确的答案,但是您可以同时使用OnClosing和OnClosed来停止相机,然后关闭您的应用程序,我不知道它在Winform中是否可以工作,但在WPF中可以与我一起工作
protected override void OnClosing(CancelEventArgs e)
{
e.Cancel = false; //prevent your application to shutdown
Camera.Stop(); //stop your camera
base.OnClosing(e);
}
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
Application.Current.Shutdown(); //then shutdown again
}
通过2步,您的相机将停止运行,而无需加入任何线程。并且请注意,这段代码是用Wpf编写的,而不是Winform编写的,但我认为您可以在Winform中找到类似的方法
希望这个答案可能对您有所帮助。