Предположим, у меня есть 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
, а не в передаваемом аргументе.