Отмените задачу и дождитесь ее завершения.

У меня есть трудоемкая задача, которую мне нужно запустить в отдельном потоке, чтобы избежать блокировки потока 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);
    }
}