TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.75K subscribers
Post #2484 2.3K
День 2056. #ЗаметкиНаПолях #Cancellation
Отмена. Часть 5: Регистрация
Регистрация — это способ для вашего кода выполнить метод обратного вызова (callback) немедленно при запросе отмены. Этот метод может выполнить некоторую операцию (часто вызов другого API) для отмены асинхронной операции.

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

Как регистрировать
Ваш код может зарегистрировать callback-метод с любым токеном отмены, вызвав его метод Register. Callback-метод вызывается, когда (если) токен отменяется. Метод Register возвращает регистрацию токена отмены (структуру IDisposable).

Практически все асинхронные API в .NET поддержку отмены через токен, поэтому код ниже в качестве примера использует устаревший WebClient, который не принимает токена отмены:
async Task DownloadAsync(CancellationToken ct)
{
using var wc = new WebClient();
using var ctr =
ct.Register(() => wc.CancelAsync());

await wc.DownloadStringTaskAsync(
new Uri("http://www.google.com"));
}

Внимание: callback-метод может не быть вызван!
Задачи всегда должны завершаться, но некоторые токены отмены никогда не будут отменены, поэтому они никогда не вызовут свои callback-методы.

Состояние гонки
Что произойдёт, если токен отмены будет отменён примерно в то же время, когда зарегистрирован обратный вызов?
Если callback-метод добавляется к токену отмены, который уже отменён, то он немедленно и синхронно вызывается.

Важность очистки
При написании отменяемого кода убедитесь, что ваш код удаляет регистрацию; это предотвратит утечки ресурсов в приложении. using var registration в коде выше является одним из распространённых способов обработки очистки.

Внимание: синхронные вызовы callback-методов
Как обсуждалось в запросе отмены, источники токенов могут быть отменены путём вызова метода Cancel. Важно отметить, что любые зарегистрированные обратные вызовы немедленно (и синхронно) запускаются методом Cancel до того, как он вернёт управление. Это может стать источником взаимоблокировок или другого неожиданного поведения. Это неудобно, поэтому в .NET 8.0 был добавлен метод токена CancelAsync, который вызывает обратные вызовы отмены в потоке из пула.

Внимание: возможно, что CancelAsync вернётся до завершения обратных вызовов, если он уже был вызван.
Как только CancellationTokenSource перейдёт в отменённое состояние, любые последующие вызовы Cancel или CancelAsync вернутся немедленно, даже если предыдущий вызов CancelAsync ещё не завершил выполнение своих обратных вызовов.

Итого
Регистрация обратных вызовов — естественный способ реализации отмены на самых низких уровнях. Однако помните, что метод обратного вызова:
1. Не должен выдавать исключений.
2. Может никогда не быть вызван.
3. Может быть вызван немедленно в том же потоке до возврата из Register.
4. В большинстве случаев вызывается синхронно.
5. Регистрация обязательно должна удаляться.

Источник:
https://blog.stephencleary.com/2024/08/cancellation-5-registration.html
  • 👍 15
More from @netdeveloperdiary
  1. Sep 28, 2026День 2798. #Оффтоп Утиная Типизация в C# с Помощью Перехватчиков. Часть 2 Некоторое время…
  2. Sep 27, 2026День 2797. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Окончание Начало Продол…
  3. Sep 26, 2026День 2796. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Продолжение Начало Три…
  4. Sep 25, 2026День 2795. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Начало Проблема с позиц…
  5. Sep 24, 2026День 2794. #Оффтоп #Здоровье Сегодня будет необычный пост. Завтра в Москве стартует конфер…
  6. Sep 23, 2026День 2793. #ЗаметкиНаПолях #SQL 10 Редких Возможностей SQL, Которые Стоит Знать Каждому. Ч…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →