2

假设我们想要显示一个对话框,当在该对话框中获得异常时task1,我们调用一个方法,该方法会启动一个新的task2. 问题是所有者窗口在task2.

请看一下简单的代码(任务并行库使用):

private void button1_Click(object sender, RoutedEventArgs e)
{   
    var scheduler = TaskScheduler.FromCurrentSynchronizationContext();
    Task.Factory.StartNew
      (() => SomeHardMethod(1)).ContinueWith(TaskContinuation, scheduler);
}
private void TaskContinuation(Task parentTask)
{   
    if (parentTask.IsFaulted)
    {
        // If we get an exception - show a dialog that starts a new task
        var dlg = new WindowDialog();  
        var scheduler = TaskScheduler.FromCurrentSynchronizationContext();
        if (dlg.Show())
        {   
          //Here we start a new task
           Task.Factory.StartNew
             (() => SomeHardMethod(2)).ContinueWith(TaskContinuation, scheduler);
        }
        var ex = parentTask.Exception;
    }
}
private void SomeHardMethod(int mode)
{   
    if (mode == 1)
    {    
         throw new ArgumentException("mode");
    }
    else
    {   //Any long operation...
        Thread.Sleep(3000);
    }    
}

对我来说,奇怪的是,当我第一次在button1_Click方法中启动任务时它不在 UI 中执行,但是当我第二次启动一个新任务时它在 UI 线程中执行,所以这就是所有者窗口冻结的原因。

谁能澄清为什么这部分代码实际上不是在后台启动任务?

if (dlg.Show())
{
    //Here we start a new task
    Task.Factory.StartNew
      (() => SomeHardMethod(2)).ContinueWith(TaskContinuation, scheduler);
}
4

1 回答 1

3

当您开始TaskusingTask.Factory.StartNew()时,将使用当前调度程序。这意味着,如果您从在 UI 线程上执行的 a 以Task这种方式启动Task,它也将在 UI 线程上执行。Task但是,如果您从 UI 线程启动 a,但在 a 之外Task(例如在您的事件处理程序中) ,则不会发生同样的情况。

为了确保在Task后台线程上执行,您需要明确指定要使用TaskScheduler.Default.

于 2013-05-11T13:34:04.350 回答