2013-05-08 2 views
1

Как определить, ожидалось ли задание или был ли его результат проверен?Определите, ожидалось ли задание

У меня есть List фонового Task S, которые создаются и активированный, но не , возможно, ждали из-за исключительное поведение. В моем «конечном» блоке мне нужно перебрать этот список и await те задачи, которые еще не были ожидаемы, чтобы предотвратить их потенциальные исключения, возникающие при их GC'd.

EDIT

Мое решение:

Во-первых, благодаря Стиву для выяснения моего устаревшее понимание того, как незамеченный исключения обрабатываются в .NET 4.5. Это очень интересно. Тем не менее, я по-прежнему заинтересован в повышении этих исключений из метода вызывающего, так что я придумал следующий простой вспомогательный класс, чтобы обеспечить простое управление Task с, не сразу заметили: использование

/// <summary> 
/// Collection of unobserved tasks. 
/// </summary> 
public class TaskCollection 
{ 
    /// <summary> 
    /// The tasks. 
    /// </summary> 
    private readonly List<Task> tasks = new List<Task>(); 

    /// <summary> 
    /// Gets a value indicating whether this instance is empty. 
    /// </summary> 
    /// <value> 
    /// <c>true</c> if this instance is empty; otherwise, <c>false</c>. 
    /// </value> 
    public bool IsEmpty 
    { 
     get 
     { 
      return this.tasks.Count == 0; 
     } 
    } 

    /// <summary> 
    /// Adds the specified task. 
    /// </summary> 
    /// <param name="task">The task.</param> 
    /// <returns>The <see cref="task"/>.</returns> 
    public Task Add(Task task) 
    { 
     Contract.Requires(task != null); 
     Contract.Requires(!this.Contains(task)); 

     Contract.Ensures(this.Contains(task)); 
     Contract.Ensures(Contract.Result<Task>() == task); 

     this.tasks.Add(task); 
     return task; 
    } 

    /// <summary> 
    /// Adds the specified task. 
    /// </summary> 
    /// <typeparam name="T">Task return type.</typeparam> 
    /// <param name="task">The task.</param> 
    /// <returns>The <see cref="task"/>.</returns> 
    public Task<T> Add<T>(Task<T> task) 
    { 
     Contract.Requires(task != null); 
     Contract.Requires(!this.Contains(task)); 

     Contract.Ensures(this.Contains(task)); 
     Contract.Ensures(Contract.Result<Task<T>>() == task); 

     this.tasks.Add(task); 
     return task; 
    } 

    /// <summary> 
    /// Determines whether [contains] [the specified task]. 
    /// </summary> 
    /// <param name="task">The task.</param> 
    /// <returns> 
    /// <c>true</c> if [contains] [the specified task]; otherwise, <c>false</c>. 
    /// </returns> 
    public bool Contains(Task task) 
    { 
     Contract.Requires(task != null); 

     return this.tasks.Contains(task); 
    } 

    /// <summary> 
    /// Observes the specified task. 
    /// </summary> 
    /// <param name="task">The task.</param> 
    /// <returns> 
    /// The task. 
    /// </returns> 
    public Task When(Task task) 
    { 
     Contract.Requires(task != null); 
     Contract.Requires(this.Contains(task)); 

     Contract.Ensures(!this.Contains(task)); 

     this.tasks.Remove(task); 
     return task; 
    } 

    /// <summary> 
    /// Observes the specified task. 
    /// </summary> 
    /// <typeparam name="T">Return type.</typeparam> 
    /// <param name="task">The task.</param> 
    /// <returns> 
    /// The task. 
    /// </returns> 
    public Task<T> When<T>(Task<T> task) 
    { 
     Contract.Requires(task != null); 
     Contract.Requires(this.Contains(task)); 

     Contract.Ensures(!this.Contains(task)); 

     this.tasks.Remove(task); 
     return task; 
    } 

    /// <summary> 
    /// Observes all tasks. 
    /// </summary> 
    /// <returns>The task.</returns> 
    public Task WhenAll() 
    { 
     Contract.Ensures(this.IsEmpty); 

     if (this.IsEmpty) 
     { 
      return TaskEx.FromResult<object>(null); 
     } 

     var taskArray = this.tasks.ToArray(); 
     this.tasks.Clear(); 

     return TaskEx.WhenAll(taskArray); 
    } 
} 

Примера:

Exception exception; 
var tasks = new TaskCollection(); 
try 
{ 
    var backgroundTask = tasks.Add(DoSomethingAsync()); 
    // Do something in parallel. 
    await tasks.When(backgroundTask); 
} 
catch (Exception ex) 
{ 
    if (tasks.IsEmpty) 
    { 
     throw; 
    } 

    exception = ex; 
} 

try 
{ 
    await tasks.WhenAll(); 
} 
catch (Exception ex) 
{ 
    exception = new AggregateException(ex, exception); 
} 

throw new AggregateException(exception); 
+0

Один комментарий здесь, вы не сможете «ждать» в блоке 'finally', так же, как вы не можете« ждать »в блоке' catch'. По крайней мере, это текущее поведение async и ожидания .NET 4.5 ... –

+0

Я думаю, вы могли бы просто перебрать все задачи и получить доступ к свойству '.Exception'. Просто выполнение этого предотвратит отбрасывание финализатора задачи. –

+1

Вы отметили этот async-ctp - вы * на самом деле * используете CTP? или это .NET 4.5? –

ответ

4

В моем блоке «finally» мне нужно перебрать этот список и ждать тех задач, которые еще не были ожидаемы, чтобы предотвратить их потенциальные исключения, возникающие при их GC'd.

Нет, вы этого не сделаете.

В .NET 4.5, unobserved task exceptions are no longer raised during finalization.

2

Вы должны быть осторожны ... как только вещи начинают получать плохо, становится трудно гарантировать, что эта задача никогда не собирается завершить (любым образом). Но - можно добавить метод, как:

public static void IgnoreFailure(this Task task) { 
    if (task.IsCompleted) { // observe now 
     // this is just an opaque method to ensure it gets evaluated 
     if (task.IsFaulted) GC.KeepAlive(task.Exception); 
    } 
    else { // observe in the future 
     task.ContinueWith(t => { 
      if (t.IsFaulted) GC.KeepAlive(t.Exception); 
     }, TaskContinuationOptions.ExecuteSynchronously); 
    } 
} 

и просто позвоните t.IgnoreFailure() на каждой задаче, была ли она ожидала, или нет.

Смежные вопросы