Отмените задачу и дождитесь ее завершения.
У меня есть трудоемкая задача, которую мне нужно запустить в отдельном потоке, чтобы избежать блокировки потока GUI. По мере продвижения этой задачи он обновляет определенный элемент управления графическим интерфейсом.
Уловка заключается в том, что пользователь может перейти к другой части графического интерфейса перед завершением задачи, и в этом случае мне нужно:
- Отменить текущую задачу (если она активна)
- Подождите, пока это будет отменено: это имеет решающее значение, поскольку задача, требующая много времени, заключается в обновлении определенного элемента управления. Если несколько потоков пытаются сделать это сразу, все может стать беспорядочным.
- Запустить задачу с нуля
Для конкретного примера, представьте, что форма состоит из двух частей: одна, где вы перемещаетесь по дереву каталогов, и еще один, где вы показываете миниатюры. Когда пользователь переходит к другому каталогу, эскизы необходимо обновить.
Сначала я подумал об использовании BackgroundWorker
и AutoResetEvent
, чтобы ждать отмены, но я, должно быть, что-то испортил, потому что я был заблокирован при отмене. Затем я прочитал о TPL, который должен заменить BGW и более примитивные механизмы.
Можно ли сделать это с помощью TPL?
Ответы
Ответ 1
Несколько замечаний:
-
Вы можете получить CancellationToken
от CancellationTokenSource
-
Отмена задачи - это совместное действие: если ваша задача не периодически проверяет свойство CancellationToken.IsCancellationRequested
, не имеет значения, сколько раз вы пытаетесь отменить задачу, это будет весело отбросьте.
В этом говорится, что общая идея:
void Main()
{
var tokenSource = new CancellationTokenSource();
var myTask = Task.Factory
.StartNew(() => DoWork(tokenSource.Token), tokenSource.Token);
Thread.Sleep(1000);
// ok, let cancel it (well, let "request it be cancelled")
tokenSource.Cancel();
// wait for the task to "finish"
myTask.Wait();
}
public void DoWork(CancellationToken token)
{
while(!token.IsCancellationRequested)
{
// Do useful stuff here
Console.WriteLine("Working!");
Thread.Sleep(100);
}
}