C#.NET任务:如何在多个任务完成时获取通知

时间:2011-08-04 14:49:12

标签: .net .net-4.0 task

在我的WPF应用程序中,我需要并行运行2个长时间运行的任务,这两个任务都返回需要在UI中显示的数据。

我的视图模型中有一个名为IsBusy的属性,在两个任务完成之前都应为true。

如何在2个长时间运行的任务完成后收到通知?

我不想使用Task.WaitAll,因为它会阻止我的UI线程。我不想使用ContinueWith链接任务,因为我希望这些长时间运行的任务并行运行。

5 个答案:

答案 0 :(得分:5)

使用TaskScheduler.FromCurrentSynchronizationContext()并将其传递给TaskFactory.ContinueWhenAll(...),以便在两个任务完成后进行UI更新。

答案 1 :(得分:4)

一种方法是创建产生这些任务的第三个线程,并使用Task.WaitAll来延迟线程退出,直到两个任务完成。在该线程结束时,您可以触发事件或执行回调函数。

使用名为BackgroundWorker的内置事件RunWorkerCompleted可以让您更轻松。这会让你进入线程池,所以你不必关心管理那个线程。

答案 2 :(得分:4)

试试Task.Factory.ContinueWhenAll。它需要一个Tasks数组,并在它们全部完成时异步触发一个操作。

答案 3 :(得分:0)

我认为你的答案是回调。

设置长时间运行的线程时,传入对方法的引用。您可以将回调方法传递给任务方法,也可以设置AsyncCallback委托实例,该实例内置于委托的BeginInvoke()功能中。

这是一个基本的例子:

public void StartMyTwoTasks()
{
   //I'm passing the callback to the task method directly; you may prefer to pass it to BeginInvoke()
   var task1Lambda = ()=>Task1(TaskCompleted);
   var task2Lambda = ()=>Task2(TaskCompleted);

   task1Lambda.BeginInvoke(null,null);
   task2Lambda.BeginInvoke(null,null);
}

public void Task1(Action<int> task1Complete)
{
   //perform your long-running calculation or data retrieval/transformation here
   Thread.Sleep(10000);
   //when finished, call the callback method.
   //You may need to use Control.Invoke() to make sure the callback is executed on the UI thread
   //If you use the AsyncCallback feature of BeginInvoke/EndInvoke, you don't have to make the call here.
   taskComplete(1);
}

public void Task2(Action<int> taskComplete)
{
   //Ditto
   Thread.Sleep(8000);

   taskComplete(2);
}

public void Task1Complete(int taskNumber)
{
   TasksComplete[taskNumber-1] = true;
   If(TasksComplete.All(x=>x==true))
      DoSomethingOnceAllTasksAreComplete();
}  

使用AsyncCallback功能,您的回调方法必须符合接受IAsyncResult的特定委托定义,但您不必担心在方法中正确调用它;框架为您处理回调:

public public void StartALongTask()
{
   var taskLambda = ()=>PerformTask();

   taskLambda.BeginInvoke(TaskComplete,null);
}

//one advantage is that you can call a method that returns a value very easily.
public IEnumerable<string> PerformTask()
{
    //long-running task
    Thread.Sleep(5000);

    return Enumerable.Repeat("result", 100);

    //look ma, no callback invocation. 
    //This makes asynchronous delegates very useful for refactoring a synchronous 
    //operation without a lot of code changes.
}

//Here's the callback, which is invoked properly by the runtime when the thread is complete
public void TaskComplete(IASyncResult ar)
{
    //calling EndInvoke on the same delegate, which is available in the AsyncResult,
    //returns the return value of that delegate as if you'd called it synchronously.
    var results = ar.AsyncDelegate.EndInvoke(ar);

    //Now you can do something with those results.
}

这两种型号都应该适合你。其他选项包括设置事件,然后在完成时由每个方法引发。它的工作方式几乎相同,因为事件实际上只是具有一些语法糖的“多播”代理。

答案 4 :(得分:0)

如果有一个与每个任务相对应的布尔标志,另一个单独的观察者线程监视这些标志呢?让每个任务在从处理返回时设置相应的标志。然后,监视线程监视是否设置了标志(即两个任务都已完成。)如果进程完成,则触发事件,将IsBusy设置为false等。