Что такое cancellation token в многопоточности?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое CancellationToken в контексте многопоточности и асинхронного программирования?
CancellationToken — это механизм в .NET для безопасной и кооперативной отмены длительных операций, особенно в многопоточных и асинхронных сценариях. Это структура (struct), которая позволяет распространять уведомление об отмене между потоками, задачами (Task) или асинхронными операциями без принудительного прерывания потоков (в отличие от устаревшего Thread.Abort()).
Основное назначение и принцип работы
Основная цель — реализация кооперативной отмены, где выполняемая операция периодически проверяет флаг отмены и корректно завершает свою работу, освобождая ресурсы. Это критически важно для:
- Отмены операций по запросу пользователя
- Ограничения времени выполнения (timeout)
- Остановки фоновых задач при завершении приложения
Источником токена является CancellationTokenSource, который создает и управляет состоянием одного или нескольких CancellationToken.
// Создание источника токена
CancellationTokenSource cts = new CancellationTokenSource();
// Получение токена из источника
CancellationToken token = cts.Token;
// Запуск задачи с передачей токена
Task.Run(() => LongOperation(token), token);
// Инициирование отмены (где-то в другом месте кода)
cts.Cancel();
Ключевые методы и свойства
Свойства токена:
IsCancellationRequested— флаг, указывающий, была ли запрошена отменаCanBeCanceled— указывает, может ли данный токен перейти в состояние отменыWaitHandle— объект синхронизации, который можно использовать для ожидания отмены
Основные методы:
ThrowIfCancellationRequested()— генерируетOperationCanceledException, если отмена запрошенаRegister()— регистрирует делегат, который будет вызван при отмене (для cleanup-логики)
Пример использования в асинхронной операции
public async Task ProcessDataAsync(CancellationToken cancellationToken)
{
for (int i = 0; i < 100; i++)
{
// Проверка отмены с выбросом исключения
cancellationToken.ThrowIfCancellationRequested();
// Или проверка с корректным завершением
if (cancellationToken.IsCancellationRequested)
{
Console.WriteLine("Операция отменена, выполняется cleanup...");
// Освобождение ресурсов
return;
}
await ProcessItemAsync(i);
await Task.Delay(100, cancellationToken); // Task.Delay тоже поддерживает отмену
}
}
// Регистрация callback при отмене
cancellationToken.Register(() =>
{
Console.WriteLine("Выполняется cleanup при отмене операции");
// Закрытие файлов, соединений и т.д.
});
Сценарии использования
- Отмена по timeout:
// Автоматическая отмена через 5 секунд
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
await LongRunningOperationAsync(cts.Token);
- Объединение нескольких источников отмены:
var userCancellation = new CancellationTokenSource();
var timeoutCancellation = new CancellationTokenSource(TimeSpan.FromSeconds(30));
// Объединение токенов: операция отменится при любой из причин
var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(
userCancellation.Token,
timeoutCancellation.Token
);
- Отмена нескольких операций одновременно:
var cts = new CancellationTokenSource();
var token = cts.Token;
// Запуск нескольких задач с одним токеном
var tasks = new List<Task>
{
Task.Run(() => Operation1(token), token),
Task.Run(() => Operation2(token), token),
Task.Run(() => Operation3(token), token)
};
// Отмена ВСЕХ операций одной командой
cts.Cancel();
Преимущества перед альтернативными подходами
- Безопасность — не принуждает потоки к немедленной остановке
- Кооперативность — задача сама решает, когда проверить отмену
- Распространение — один токен можно передать в цепочку вызовов
- Композиция — возможность объединения нескольких токенов
- Resource cleanup — гарантирует возможность освобождения ресурсов
Важные практики
- Всегда передавайте токен в асинхронные методы, если они поддерживают отмену
- Не блокируйте в обработчиках
Register()— это может задержать отмену - Освобождайте
CancellationTokenSourceчерезDispose()илиusing - Обрабатывайте
OperationCanceledExceptionна верхнем уровне для корректного завершения
Отличия от Thread.Abort()
| CancellationToken | Thread.Abort() |
|---|---|
| Кооперативная отмена | Принудительная остановка |
| Безопасна для состояния приложения | Может оставить данные в некорректном состоянии |
| Позволяет cleanup | Нет гарантии выполнения cleanup |
| Не портит стек потока | Вызывает ThreadAbortException в любом месте |
CancellationToken стал стандартным способом обработки отмены в .NET, особенно с распространением async/await паттерна. Его правильное использование значительно повышает надежность и отзывчивость многопоточных приложений, позволяя пользователям прерывать длительные операции без риска повреждения состояния приложения.