Task и Task.WaitAll с обработкой исключений тайм-аута - PullRequest
5 голосов
/ 18 августа 2011

При ожидании задач с помощью Task.WaitAll и указании тайм-аута, если время ожидания WaitAll истекло, нужно ли мне также отдельно наблюдать за незавершенными задачами (например, путем регистрации продолжения)?

Этот поток1004 * заставляет меня думать, что ответ - да, но я не нашел ничего другого, подтверждающего это.

var random = new Random();
var tasks = Enumerable.Range(0, 10).Select((i) => Task.Factory.StartNew(() => {
        // Sleep 5-15 seconds
        Thread.Sleep(random.Next(5000, 15000));
        throw new Exception("Some exception.");
    }
)).ToArray();

try {
    // Wait for 10 seconds
    Task.WaitAll(tasks, 10000);
} catch (AggregateException) {
    // Swallow
}

// Check to see how many tasks were unfinished
tasks.Where(t => !t.IsCompleted).Count().Dump("Unfinished count: ");

// Is this neccessary to avoid exceptions being thrown on the finalizer?
foreach (Task task in tasks) {
    task.ContinueWith(t => t.Exception, TaskContinuationOptions.OnlyOnFaulted);
}

Ответы [ 2 ]

2 голосов
/ 23 августа 2011

Чтобы избежать сбоя финализатора, вы должны соблюдать исключения, выдаваемые телом Task. Чтобы соблюсти исключение Task, вам нужно выполнить одно из следующих действий:

  1. Доступ к свойству исключения
  2. Звоните Task.Wait / WaitAll / WaitAny
  3. Зарегистрировать продолжение, которое запускается только в случае сбоя задачи

То, что вы сделали, определенно необходимо, чтобы избежать сбоя финализатора.

0 голосов
/ 18 августа 2011

Тестирование с помощью LINQPad v4.31 показывает, что ответ - да, поскольку, если вы закомментируете foreach, вы получаете необработанное диалоговое окно исключений для каждой незавершенной задачи.

Мне кажется, я понимаю, почему это происходит на данный момент, ноесли кто-то хочет получить более техническое объяснение этого поведения, то обязательно сделайте это.

...