Подтвердить что ты не робот

Как получить уведомление о завершении System.Threading.Tasks.Task

В настоящее время я заменяю некоторые домашние функции задачи с новой реализацией, используя новую функциональность System.Threading.Tasks, найденную в .net 4.

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

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

Все примеры, которые я видел, используют либо Wait() для задачи, пока не завершатся, либо не ссылаются на параметр результата в задаче. Оба из них заблокируют поток, который запустил Task, чего я не хочу.

Некоторые решения, о которых я подумал:

  • Создайте новый поток и запустите задачу, затем используйте Wait() или .Result, чтобы заблокировать новый поток и как-то синхронизировать результат с вызывающим, возможно, с опросом в заданиях параметра IsCompleted.

  • Задайте задачу "Уведомлять завершенную", которую я могу запустить после завершения задачи, которую я хочу запустить, а затем вызывает статическое событие или что-то еще.

  • Передайте делегат во входную часть задачи и вызовите это, чтобы уведомить, что задача завершена.

Я могу думать или плюсы и минусы для всех из них, но мне особенно не нравится идея явно создать новый поток, чтобы запустить задачу, когда одна из целей использования класса Task в первое место - абстрагироваться от прямого использования Thread.

Любые мысли о лучшем способе? Я что-то пропустил? Будет ли событие "Завершено" слишком много, чтобы просить:)? (Конечно, есть веская причина, почему нет никого!)

4b9b3361

Ответ 1

Я подозреваю, что вы ищете Task.ContinueWith (или Task<T>.ContinueWith). В основном они говорят: "Когда вы закончили эту задачу, выполните это действие". Однако есть различные варианты, которые вы можете указать, чтобы взять на себя больше контроля над ним.

MSDN более подробно описывает это в "Как выполнить несколько задач с продолжением" и "Задачи продолжения" .

Ответ 2

В современном С# вам больше не нужно явно вызывать ContinueWith(). Альтернативой исходному принятому ответу было бы просто создать метод async, который находится в await Task, и делает все, что захочет, когда завершается Task.

Например, предположим, что вы хотите поднять событие под названием TaskCompleted, когда завершается Task. Вы должны написать такой метод, как:

async Task RaiseEventWhenTaskCompleted(Task task)
{
    await task;
    TaskCompleted?.Invoke(this, EventArgs.Empty);
}

Чтобы "зарегистрировать" ожидание, просто вызовите вышеуказанный метод. Добавьте обработку исключений по желанию либо в метод выше, либо в некоторый код, который в конечном итоге будет наблюдать Task, возвращенный вышеуказанным методом.

Ответ 4

Вы можете использовать функцию ContinueWith с вашей подпрограммой в качестве первого аргумента и планировщик задач в качестве второго аргумента, заданного TaskScheduler.FromCurrentSynchronizationContext().

Это выглядит так:

var task1 = new Task(() => {do_something_in_a_remote_thread();} );

task1.ContinueWith(() =>  {do_something_in_the_ui_thread();},
TaskScheduler.FromCurrentSynchronizationContext());

Ответ 5

 Task task = Task.Run ( () => { Thread.Sleep ( 2000 ); } );

 task.GetAwaiter ().OnCompleted ( () => 
   {
     MessageBox.Show ( "the task completed in the main thread", "");
   } );