Task.WhenAll不按预期抛出异常

时间:2017-03-15 18:08:35

标签: c# multithreading asynchronous

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

    // Class variables
    private String token_resource = "/yourApp/oauth/token?username=";
    private String endpoint_rest="https://your.app.domain.com/";
    private String acessToken;

    @When("^user gets access token using userId \"(.+)\" and password \"(.+)\"$")
public void getAccessToken(String userName, String password){
    RequestSpecification requestSpec = RestAssured.with();
    requestSpec.given().contentType("application/json");
    requestSpec.headers("Authorization", "Basic  your-string-here");
    Response response = requestSpec.post(endpoint_rest + token_resource + userName + "&password=" + password + "&client_id=yourApp&grant_type=password");
    String responseMsg = response.asString();
    System.out.println(">> responseMsg=" + responseMsg);
    assertTrue("Missing access token",responseMsg.contains("access_token"));
    System.out.println(">> Get Access token RESPONSE: " + responseMsg);

    DocumentContext doc = JsonPath.parse(responseMsg);
    acessToken= doc.read("access_token");

    System.out.println(" >> doc.read access_token= " + acessToken);  
}

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

    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"));
            }
        }
    }

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

任何人都知道我做错了什么?

谢谢!

1 个答案:

答案 0 :(得分:4)

这一行

await Task.WhenAll(task1, task2);

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

但是要发生这种情况(即你接收AggregateException)所有任务应该完成执行。

因此,在当前状态下,当两个任务中出现异常时(迟早),您将收到异常

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

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

根据评论更新

为了澄清,Task.WhenAll(..)将返回任务。完成此任务后,它将包含AggregateException,其Exception属性中的所有失败任务都有例外。

如果您await执行此类任务,它将从列表中的第一个故障任务中抛出未解包的异常。

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