2014-11-06 30 views
2

我試圖使用Task.WaitAny等待一堆任務,但我真正想要的是等待第一個RanToCompletion任務,而不是Canceled任務。如何等待第一個任務後RanToCompletion

所以當我有一大堆的任務,其地位就像:

0 Canceled;1 Canceled;2 Canceled;3 Canceled;4 Canceled;5 RanToCompletion;

理想我想Task.WaitAny返回5但它返回什麼是0

我該如何等待第一次RanToCompletion任務?

+2

如果所有的5失敗?我的意思是什麼都沒有完成。你想幹什麼? – 2014-11-06 07:44:34

+0

^ 他表示第一個完成rantcompletion,所以他可能有超過五個,只是等待一個任務完成。 – DevEstacion 2014-11-06 07:45:30

+0

@RonaldEstacion我的問題是如果一切都失敗了。 5只是一個從問題推斷的數字。 – 2014-11-06 07:46:32

回答

3

沒有開箱即用的東西。我們需要編寫一些輔助方法,如評論中所述。

這是一個使用TaskCompletionSource的實現。

public class MyTask 
{ 
    private readonly TaskCompletionSource<Task> completionSource = new TaskCompletionSource<Task>(); 

    private readonly Task[] tasks; 
    private int numberOfTasks; 
    private MyTask(Task[] tasks) 
    { 
     if (tasks.Length == 0) 
     { 
      throw new ArgumentException("No tasks"); 
     } 

     this.tasks = tasks; 
     this.numberOfTasks= tasks.Length; 
    } 

    private int WaitAnyInternal() 
    { 
     foreach (var task in tasks) 
     { 
      task.ContinueWith(task1 => completionSource.TrySetResult(task1), TaskContinuationOptions.OnlyOnRanToCompletion); 
     } 
     foreach (var task in tasks) 
     { 
      task.ContinueWith(task1 => 
      { 
       if (Interlocked.Decrement(ref numberOfTasks) == 0) 
       { 
        completionSource.SetCanceled(); 
       } 
      }, TaskContinuationOptions.NotOnRanToCompletion); 
     } 

     try 
     { 
      completionSource.Task.Wait(); 
     } 
     catch (AggregateException ex) 
     { 
      if (ex.Flatten().InnerExceptions.OfType<OperationCanceledException>().Any()) 
      { 
       return -1; 
      } 
     } 

     return Array.IndexOf(tasks, completionSource.Task.Result); 
    } 

    public static int WaitAnyRanToCompletion(params Task[] tasks) 
    { 
     return new MyTask(tasks).WaitAnyInternal(); 
    } 
} 

然後用它作爲:

var task1 = Task.Run(() => 
{ 
    Thread.Sleep(1000); 
    throw new Exception(); 
});//Faulted task 

var task2 = Task.Run(() => 
{ 
    Thread.Sleep(5000); 
});//Will complete first 

var task3 = Task.Delay(10000);//Will complete, but not first 

int index = MyTask.WaitAnyRanToCompletion(task1, task2, task3); 
//Index will be 1, which means task2