异步等待块主UI

时间:2013-10-06 07:13:39

标签: c# multithreading asynchronous async-await c#-5.0

我正在使用新的async await功能从C#中的backgroundworker升级。在下面的代码中,我试图用ContinueWith方法复制多个任务的执行。

        Task t1 = new Task
        (
            () =>
            {
                Thread.Sleep(10000);

                // make the Task throw an exception
                MessageBox.Show("This is T1");
            }
        );

        Task t2 = t1.ContinueWith
        (
            (predecessorTask) =>
            {

                if (predecessorTask.Exception != null)
                {
                    MessageBox.Show("Predecessor Exception within Continuation");

                    return;
                }

                Thread.Sleep(1000);
                MessageBox.Show("This is Continuation");
            },

            TaskContinuationOptions.AttachedToParent | TaskContinuationOptions.OnlyOnRanToCompletion
        );

        t1.Start();

        try
        {
           t1.Wait(); <------ Comment 
           t2.Wait(); <------ Comment 
        }
        catch (AggregateException ex)
        {
            MessageBox.Show(ex.InnerException.Message);
        }  

我的问题是当我评论t1.wait和t2.wait时任务没有阻止UI。但是当我取消注释t1.wait和t2.wait UI阻塞直到线程完成。期望的行为是在不阻止UI的情况下捕获try / catch块中的错误。我错过了什么?

3 个答案:

答案 0 :(得分:4)

如果这是在UI事件处理程序中运行,则可以将async修饰符添加到方法签名中,并将t1.Wait()更改为await t1。这将返回对UI线程的控制,并且当Thread.Sleep完成时,将继续执行继续,并且将捕获任何异常。

答案 1 :(得分:3)

当你使用Task.Wait()时,你基本上是在说“等我的任务完成”。这就是你阻止线程的原因。处理任务中的异常的一种好方法是使用Task.ContinueWith重载并将OnlyOnFaulted作为TaskContinuationOption传递,如下所示:

Task yourTask = new Task {...};
yourTask.ContinueWith( t=> { /*handle expected exceptions*/ }, TaskContinuationOptions.OnlyOnFaulted );

答案 2 :(得分:3)

如果您要使用Task-based Asynchronous Pattern,则应使用建议的指南。我有MSDN article描述了其中许多内容。

特别是:

  • Task.Run使用Task代替Task.Start构造函数。
  • 使用await代替ContinueWith
  • 请勿使用AttachedToParent

如果您应用这些更改,您的代码将如下所示:

try
{
  await Task.Run(() =>
  {
    Thread.Sleep(10000);

    // make the Task throw an exception
    MessageBox.Show("This is T1");
  });
  await Task.Run(() =>
  {
    Thread.Sleep(1000);
    MessageBox.Show("This is Continuation");
  });
}
catch (Exception ex)
{
  MessageBox.Show(ex.Message);
}