По событию создается долгоживущая задача:
Task.Run(()=> ...
Таких задач может одновременно быть много. Нужно: завершить все задачи и дождаться пока они все заврешат работу (внутри задачи могут быть не асинхронные вызовы, которые отменить с помощью CancellationToken нельзя).
Вот тестовый код:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp45
{
class Program
{
private static readonly CancellationTokenSource TokenSource = new CancellationTokenSource();
static async Task Main(string[] args)
{
var cancellationToken = TokenSource.Token;
AddTasksPeriodically(cancellationToken);
Thread.Sleep(1000);
await StopAllTasksAndWait();
Console.WriteLine("StopAllTasksAndWait");
Console.ReadKey();
Console.WriteLine("Hello World!");
}
static async Task StopAllTasksAndWait()
{
// Вот тут нужно отменить все и дождаться (вернуть Task) когда все задачи будут завершены
}
static void AddTasksPeriodically(CancellationToken cancellationToken)
{
// Одновременно стартуем 10 задач
for (int taskId = 1; taskId <= 10; taskId++)
{
int taskIdCopy = taskId;
if (cancellationToken.IsCancellationRequested)
break;
var task = Task.Run(async () =>
{
Console.WriteLine("Begin " + taskIdCopy);
Thread.Sleep(2000); // Вызываем синхронный метод без возможности отмены
Console.WriteLine("End " + taskIdCopy);
await Task.Delay(4000, cancellationToken); // Задержка
}, cancellationToken);
}
}
}
}
Решение:
| Скрытый текст |
| using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp45
{
class Program
{
private static readonly CancellationTokenSource TokenSource = new CancellationTokenSource();
private static readonly ConcurrentDictionary<int, Task> Tasks = new ConcurrentDictionary<int, Task>();
static async Task Main(string[] args)
{
var cancellationToken = TokenSource.Token;
AddTasksPeriodically(cancellationToken);
Thread.Sleep(1000);
await StopAllTasksAndWait();
Console.WriteLine("StopAllTasksAndWait");
Console.ReadKey();
Console.WriteLine("Hello World!");
}
static async Task StopAllTasksAndWait()
{
Console.WriteLine("Cancel");
TokenSource.Cancel();
try
{
await Task.WhenAll(Tasks.Values);
}
catch (TaskCanceledException taskCanceledException)
{
Console.WriteLine("TaskCanceledException");
}
catch (AggregateException aggregateException)
{
Console.WriteLine("AggregateException (cnt=" + aggregateException.InnerExceptions.Count + ")");
}
}
static void AddTasksPeriodically(CancellationToken cancellationToken)
{
// Одновременно стартуем 10 задач
for (int taskId = 1; taskId <= 10; taskId++)
{
int taskIdCopy = taskId;
if (cancellationToken.IsCancellationRequested)
break;
var task = Task.Run(async () =>
{
Console.WriteLine("Begin " + taskIdCopy);
Thread.Sleep(2000); // Вызываем синхронный метод без возможности отмены
Console.WriteLine("End " + taskIdCopy);
await Task.Delay(4000, cancellationToken); // Задержка
Tasks.TryRemove(taskIdCopy, out _); // Удаляем из списка (уже исполнена, нет смысла ждать завершения)
}, cancellationToken);
Tasks.TryAdd(taskIdCopy, task); // Добавляем в список на ожидание
}
}
}
}
|
| |
Смущает что контроль хода программы организован через Exception. Как лучше?