线程谜题 - 等待来自 UI 个线程的线程 (C#)
Thread puzzle - waiting for thread from UI thread (C#)
我有一个奇怪的先有鸡还是先有蛋的问题:
我有一个从相机拍摄图像并将它们放在 UI (WPF) 上的任务。
当我退出应用程序 window 时,我想正确关闭相机,所以我调用了 Dispose()。但是,如果缓冲区中仍有图像,相机将无法关闭,所以我必须等待该线程完成(我通过更改 "isLive" 布尔值触发线程停止)。
但是,线程使用了从 UI 到 post 图像的 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
}
您可以将 UIDispatcher.Invoke
更改为 UIDispatcher.BeginInvoke
以避免同步调用 UI 线程。然后,但是,您需要确保在 UI 线程转换图像时 rawImage
仍然有效。因此,必须将 rawImage
的所有权移至 Action 对象以避免数据竞争。
您可以在 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();
}
我有一个奇怪的先有鸡还是先有蛋的问题:
我有一个从相机拍摄图像并将它们放在 UI (WPF) 上的任务。 当我退出应用程序 window 时,我想正确关闭相机,所以我调用了 Dispose()。但是,如果缓冲区中仍有图像,相机将无法关闭,所以我必须等待该线程完成(我通过更改 "isLive" 布尔值触发线程停止)。
但是,线程使用了从 UI 到 post 图像的 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
}
您可以将 UIDispatcher.Invoke
更改为 UIDispatcher.BeginInvoke
以避免同步调用 UI 线程。然后,但是,您需要确保在 UI 线程转换图像时 rawImage
仍然有效。因此,必须将 rawImage
的所有权移至 Action 对象以避免数据竞争。
您可以在 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();
}