我有一个奇怪的鸡蛋类问题:
我有一个任务,从相机拍摄图像并将它们放在UI(WPF)上。 当我退出应用程序窗口时,我想要正确关闭相机,所以我调用Dispose()。但是,如果缓冲区中仍然存在图像,则摄像机无法关闭,因此我必须等待该线程完成(我通过更改“isLive”布尔值来触发线程停止)。
但是,线程使用UI中的Dispatcher发布图像。从UI线程调用线程上的“Wait()”使得它停止UI线程,这反过来在尝试更新UI时使相机线程停顿,使其无限期挂起。
以下是我的代码的简单版本。有没有办法解决这个问题?
public void GoLive()
{
isLive = true;
cameraTask = Task.Run(new Action(() =>
{
cam.BeginAcquisition();
while (isLive)
{
var rawImage = cam.GetNextImage(); // gets raw img from camera buffer
// now make image appear on my UI
UIDispatcher.Invoke(new Action(() =>
{
// this happens on the UI thread
uiImage = ConvertRawToBitmapSource(rawImage);
}));
}
}
// when you click to exit the window, this Dispose() method gets called:
public void Dispose()
{
isLive = false; // a field boolean
cameraTask.Wait(); // <------ hangs here infinitely!!!
cam.DeInit(); // shut down the camera
}
答案 0 :(得分:1)
您可以简单地在UI线程中运行采集循环,并在单独的任务中获取每个帧。现在您需要做的就是设置isLive = false:
。
public async Task RunAcquisition()
{
cam.BeginAcquisition();
while (isLive)
{
var rawImage = await Task.Run(() => cam.GetNextImage());
uiImage = ConvertRawToBitmapSource(rawImage);
}
cam.DeInit();
}
相机甚至可能有一个等待GetNextImageAsync
方法,这将进一步简化你的循环:
public async Task RunAcquisition()
{
cam.BeginAcquisition();
while (isLive)
{
var rawImage = await cam.GetNextImageAsync();
uiImage = ConvertRawToBitmapSource(rawImage);
}
cam.DeInit();
}
答案 1 :(得分:0)
您可以将UIDispatcher.Invoke
更改为UIDispatcher.BeginInvoke
,以避免同步调用UI线程。然而,然后,当UI线程转换图像时,您需要确保rawImage
仍然有效。因此,必须将rawImage
的所有权移至Action对象以避免数据争用。