gpt4 book ai didi

c# - Task.WhenAll 没有按预期抛出异常

转载 作者:行者123 更新时间:2023-12-03 13:14:17 32 4
gpt4 key购买 nike

我有两个异步方法作为单独的线程/任务在窗体窗口的后台运行。这些是无限循环,只是在后台做一些工作,然后使用调度程序更新 UI。见下文。

    public async Task RunCameraThread(CancellationToken cancelToken)
{
while (true)
{
// If cancellation token is set, get out of the thread & throw a cancel exception
cancelToken.ThrowIfCancellationRequested();

// Get an image from the camera
CameraBitmap = Camera.CaptureImage(true);

// Update the UI (use lock to prevent simultaneous use of Dispatcher object in other thread)
lock (Dispatcher)
{
Dispatcher.Invoke(() => pictureBoxCamera.Image = tempBitmap);
Dispatcher.Invoke(() => pictureBoxCamera.Invalidate());
}
}
}

public async Task RunDistanceSensorThread(CancellationToken cancelToken)
{
while (true)
{
// If cancellation token is set, get out of the thread & throw a cancel exception
cancelToken.ThrowIfCancellationRequested();

// Get the distance value from the distance sensor
float distance = Arduino.AverageDistance(10, 100);

// Update the UI (use lock to prevent simultaneous use of Dispatcher object)
lock (Dispatcher)
{
Dispatcher.Invoke(() => textBoxDistanceSensor.Text = distance.ToString("0.00"));
}
}
}

这些任务是通过单击按钮启动的(代码如下所示)。我正在尝试使用 await Task.WhenAll 来等待这两个任务。设置取消 token 后,这将按预期工作并捕获 OperationCanceledException。然而,相机或 Arduino 问题引发的任何异常(通过在运行期间简单地拔下 USB 进行模拟)似乎都没有被捕获。

    private async void buttonConnect_Click(object sender, EventArgs e)
{
try
{
// Disable UI so we cannot click other buttons
DisableComponentsUI();
// Connect to Nimbus, Camera and Arduino
await Task.Run(() => Nimbus.ConnectAsync());
Camera.Connect();
Camera.ManagedCam.StartCapture();
Arduino.Connect();
// Get the current Nimbus positions and enable UI
UpdatePositionsUI();
EnableComponentsUI();
// Reset cancel token and start the background threads and await on them (this allows exceptions to bubble up to this try/catch statement)
StopTokenSource = new CancellationTokenSource();
var task1 = Task.Run(() => RunCameraThread(StopTokenSource.Token));
var task2 = Task.Run(() => RunDistanceSensorThread(StopTokenSource.Token));
await Task.WhenAll(task1, task2);
}
catch (OperationCanceledException exceptionMsg)
{
// Nothing needed here...
}
catch (Hamilton.Components.TransportLayer.ObjectInterfaceCommunication.ComLinkException exceptionMsg)
{
NimbusExceptionHandler(exceptionMsg);
}
catch (FlyCapture2Managed.FC2Exception exceptionMsg)
{
CameraExceptionHandler(exceptionMsg);
}
catch (IOException exceptionMsg)
{
ArduinoExceptionHandler(exceptionMsg);
}
catch (UnauthorizedAccessException exceptionMsg)
{
ArduinoExceptionHandler(exceptionMsg);
}
catch (TimeoutException exceptionMsg)
{
ArduinoExceptionHandler(exceptionMsg);
}
}

奇怪的是,我在输出窗口中看到了抛出的异常,但它们并没有冒泡到我的 try/catch。此外,如果我只是等待一项任务,它会按预期工作,并且会出现异常。

有人知道我做错了什么吗?

谢谢!

最佳答案

这一行

await Task.WhenAll(task1, task2);

如果它发生在 task1 和/或 task2 中,将抛出 AggregateException,并将包含来自内部所有任务的异常。

但要发生这种情况(即您收到 AggregateException)所有任务应该完成它们的执行。

因此,在您当前的状态下,您将在两个任务中都发生异常时(迟早)收到异常。

如果您确实需要在其中一个任务失败时停止所有其他任务,您可以尝试使用例如 Task.WhenAny 而不是 Task.WhenAll.

另一种选择是实现一些手动同步 - 例如,引入共享标志,如“wasAnyExceptions”,每当该任务中发生异常时将其设置在每个任务中,并在任务循环中检查它以停止循环执行。

更新基于评论

为了澄清,Task.WhenAll(..) 将返回任务。当此任务完成时,它将包含 AggregateException 及其 Exception 属性中所有失败任务的异常。

如果您await 这样的任务,它将从列表中的第一个错误任务中抛出未包装的异常。

如果您为此任务.Wait(),您将收到AggregateException

关于c# - Task.WhenAll 没有按预期抛出异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42817500/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com