Обновить

История небольшого бага с использованием SemaphoreSlim в C#

Где-то на сервере жил-был код:

try
{
  await semaphoreSlim.WaitAsync(cancellationToken);
  await DoSomething();
}
finally
{
  semaphoreSlim.Release();  
}

Ничего интересного: ожидаем семафор, делаем какую-то работу и по завершении освобождаем в Release.

Всё работало нормально, но в какой-то момент стали проскакивать исключенияSemaphoreFullException. Чтобы понять, когда они возникают, нужно вспомнить, как работает SemaphoreSlim.

SemaphoreSlim - имеет 2 основных параметра: текущее значение и максимальное. WaitAsync - уменьшает текущее значение на один, Release - увеличивает. Если вызывать WaitAsync, когда текущее значение равно 0, то нужно дождаться вызова Release. Если вызывать Release, когда текущее значение равно максимальному, то будет выброшено исключение SemaphoreFullException.

Получается, что Release вызывается больше раз чем WaitAsync. Как такое может быть? По коду - никак. Но, по факту, важен не сам вызов WaitAsync, а изменение текущего значения счётчика.

Всё дело в cancellationToken. Если запрошена отмена операции, то WaitAsync бросает исключение до изменения текущего значения. Далее в блоке finally исходное исключение перекрывается другим исключением, и мы теряем исходную ошибку.

Т.е. правильный код должен выглядеть вот так:

await semaphoreSlim.WaitAsync(cancellationToken);
try
{
  await DoSomething();
}
finally
{
  semaphoreSlim.Release();  
}

И невероятный фикс с перемещением строчки уезжает на тестирование.

Теги:
Всего голосов 3: ↑3 и ↓0+5
Комментарии6

Россиянам стал доступен цифровой рубль. Главное

С 1 сентября 2026 года цифровой рубль становится доступен гражданам и компаниям России. Цифровой рубль — третья форма российской валюты наряду с наличными и безналичными рублями. Его также эмитирует Банк России, а все три формы рубля равны между собой.

Россиянам стал доступен цифровой рубль. Главное

Публикации