Вам необходимо использовать SemaphoreSlim
для статического объекта с одинарной областью действия.Это может быть ваш репозиторий или что-то в этом роде, или если вам нужно сохранить это в области запросов, то вы можете использовать альтернативный вспомогательный класс для простой обработки этого процесса приращения.Семафоры довольно просты в использовании;в основном вы просто устанавливаете статический ивар, набранный как SemaphoreSlim
:
private static SemaphoreSlim _semaphore = new SemaphoreSlim(1);
Здесь 1
указывает, что только один объект может входить в семафор за один раз, что вы хотите для этого конкретного сценария,Вы можете использовать другие числа здесь в различных сценариях, чтобы ограничить скорость.Затем вы оборачиваете код, который вам нужен для запуска:
_semaphore.Wait(); // or await _semaphore.WaitAsync()
// code protected by semaphore here
_semaphore.Release();
У семафора есть счетчик.Когда вызывается Wait
, семафор увеличивает счетчик на 1, а затем, если больше ничего не ждет, он вернется и позволит обрабатывать последующий код.Если счетчик уже выше максимального значения (здесь 1), он не вернется, пока счетчик не опустится ниже максимального порога.Это уменьшение происходит через Release
, который вызывается после завершения вашего кода.По сути, это создает тип очереди, в которой другие потоки ожидают возможности выполнить код, защищенный семафором.Это позволяет вам гарантировать, что только один Save
вызов за раз делает что-либо, и, следовательно, ваша инкрементная транзакция всегда будет работать.
Это похоже на блокировку, особенно со счетчиком 1, но семафорыпотокобезопасен, тогда как блокировки не являются.Если что-то еще уже имеет блокировку, то вы просто получите исключение, пытаясь создать блокировку, и вам придется восстанавливать вручную, применяя шаблон ожидания и повторения, прерыватель цепи и т. Д. Семафоры облегчают это, не привязываясь клюбая конкретная нить.