Как остановить асинхронную задачу? - PullRequest
0 голосов
/ 31 октября 2018

Предположим, у меня есть List<Task>, который помогает мне управлять всеми задачами на основе индекса:

private List<Task> tasks = new List<Task>(new Task[3]);

При запуске приложения отображается меню, и пользователь может выбрать, какую задачу можно запустить, просто:

public void Menu()
{
    Console.WriteLine("1. Task");
    Console.WriteLine("2. Task");
    Console.WriteLine("3. Task");
    Console.WriteLine("0. Exit");

    ConsoleKeyInfo input;

    do
    {
        input = Console.ReadKey();
        Console.WriteLine();

        switch (input.Key)
        {
            case ConsoleKey.NumPad1:
                 StartTask(1);
                 break;
            case ConsoleKey.NumPad2:
                 StartTask(2);
                 break;
            case ConsoleKey.NumPad3:
                 StartTask(3);
                 break;
        }
     } while (input.Key != ConsoleKey.NumPad0);
}

внутри метода StartTask Я передаю число Task для выполнения, это логика:

public void StartTask(int instance)
{
    int index = instance - 1;

    //Task not yet instantiated, create new one
    if(tasks.ElementAtOrDefault(index) == null)
    {
        //Make a new cancellation token
        cts.Insert(index, new CancellationTokenSource());

        tasks.Insert(index, new Task(async () => 
        {
            await foo.DoWork(cts[index].Token);
        }, cts[index].Token));

        if(!tasks[index].Status.Equals(TaskStatus.Running))
        {
            tasks[index].Start();
        }
    }
}

Как видите, у меня также есть List<CancellationTokenSource> cts, который помогает мне завершить задачу. Метод Cancel находится в другом меню, как указано выше.

Теперь проблема довольно ясна: я не могу этого сделать, потому что проверка выполняется до операции await для DoWork();, которая содержит это:

public class Foo
{
     private async Task DoWorkAsync(CancellationToken token)
     {
         while (!token.IsCancellationRequested)
         {
             string newData = DateTime.Now.ToLongTimeString();

             Console.WriteLine(newData);
              await Task.Delay(200);
         }
     }
}

по существу: как я могу остановить Task, который выполняет loop с CancellationToken?

Маркер, переданный в качестве параметра, не может изменить значение, если остановка выполняется после запуска. По сути, значение IsCancellationRequested изменяется только в контексте класса Task, а не в передаваемом аргументе.

1 Ответ

0 голосов
/ 31 октября 2018

Передайте токен отмены в DoWorkAsync. И используйте его в цикле while как условие.

while(!token.IsCancellationRequested)
{ 
   await Task.Delay(200, token); 
}

'token' должен быть передан как параметр. Если честно, я думаю, что в вашем решении слишком много избыточного кода ...

Как отменить задачу, используя источник токена отмены:

void CancelTask(int taskNumber)
{
   int index = taskNumber - 1;
   cts[index].Cancel();
}

Этот код установит флаг IsCancellationRequested для «токена», который вы используете в цикле, в значение «true».

...