【发布时间】:2017-08-06 15:34:18
【问题描述】:
我有两个异步方法作为单独的线程/任务在表单窗口的后台运行。这些是无限循环,只是在后台做一些工作,然后使用调度程序更新 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 来等待这两个任务。设置取消令牌后,这将按预期工作并捕获 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。此外,如果我只是等待一项任务,它会按预期工作并且异常会冒泡。
有人知道我做错了什么吗?
谢谢!
【问题讨论】:
-
@StenPetrov 是的,我期待这一点。它似乎确实引发了异常,因为我可以在输出窗口中看到它,但是在使用 .WhenAll 时它不会冒泡到我的 try/catch
-
@StenPetrov
WhenAll将抛出一个AggregateException,其中包含来自每个出错任务的每个异常的异常,而不仅仅是第一个。 -
@servy 感谢您的澄清,我确实在最后一个示例
await Task.WhenAll中找到了相同的语法 here,但是对于这个问题可能很重要的警告是:“任务可能是调用Task.WhenAll的结果。当你等待这样一个任务时,只会捕获一个异常,你无法预测会捕获哪个异常。”。 -
看这里,可能有帮助codeblog.jonskeet.uk/2010/11/04/…
-
@leonhart88:问题在您发布的代码中并不明显。试试reducing to a minimal, complete example,你可能会自己发现解决方案。
标签: c# multithreading asynchronous