Каковы преимущества использования `lock` по сравнению с `SemaphoreSlim`?

Я опаздываю на вечеринку, но недавно узнала о SemaphoreSlim:

Раньше я использовал lock для синхронной блокировки и логическое значение busy для асинхронной блокировки. Теперь я просто использую SemaphoreSlim для всего.

private SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1);

private void DoStuff()
{
    semaphoreSlim.Wait();
    try
    {
        DoBlockingStuff();
    }
    finally
    {
        semaphoreSlim.Release();
    }
}

Против

private object locker = new object();

private void DoStuff()
{
    lock(locker)
    {
        DoBlockingStuff();
    }
}

Есть ли какие-либо синхронные случаи, когда я должен предпочесть использовать lock вместо SemaphoreSlim? Если так, то кто они?

Как настроить Tailwind CSS с React.js и Next.js?
Как настроить Tailwind CSS с React.js и Next.js?
Tailwind CSS - единственный фреймворк, который, как я убедился, масштабируется в больших командах. Он легко настраивается, адаптируется к любому...
LeetCode запись решения 2536. Увеличение подматриц на единицу
LeetCode запись решения 2536. Увеличение подматриц на единицу
Увеличение подматриц на единицу - LeetCode
Переключение светлых/темных тем
Переключение светлых/темных тем
В Microsoft Training - Guided Project - Build a simple website with web pages, CSS files and JavaScript files, мы объясняем, как CSS можно...
Отношения "многие ко многим" в Laravel с методами присоединения и отсоединения
Отношения "многие ко многим" в Laravel с методами присоединения и отсоединения
Отношения "многие ко многим" в Laravel могут быть немного сложными, но с помощью Eloquent ORM и его моделей мы можем сделать это с легкостью. В этой...
В PHP
В PHP
В большой кодовой базе с множеством различных компонентов классы, функции и константы могут иметь одинаковые имена. Это может привести к путанице и...
Карта дорог Беладжар PHP Laravel
Карта дорог Беладжар PHP Laravel
Laravel - это PHP-фреймворк, разработанный для облегчения разработки веб-приложений. Laravel предоставляет различные функции, упрощающие разработку...
3
0
92
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вот несколько преимуществ lock перед SemaphoreSlim:

  1. Lock является реентерабельным, а SemaphoreSlim — нет. Так что программирование с помощью lock более снисходительно. В случае, если в вашем приложении есть редкий путь, где вы дважды получаете одну и ту же блокировку, lock получит ее успешно, а SemaphoreSlim заблокирует.

  2. Lock — это синтаксический сахар класса Monitor. Другими словами, для Monitor в C# есть языковая поддержка, а для SemaphoreSlim нет. Таким образом, использование lock сравнительно более удобно и менее многословно.

  3. Вы можете написать более надежный код с помощью lock, потому что вы можете добавить отладочные утверждения во вспомогательные методы, что блокировка была получена: Debug.Assert(Monitor.IsEntered(_locker));

  4. Статистику конфликтов можно получить с помощью свойства Monitor.LockContentionCount: «Получает, сколько раз возникали конфликты при попытке получить блокировку монитора». Статистики по классу SemaphoreSlim нет.

  5. SemaphoreSlim есть IDisposable, поэтому вам нужно подумать о том, когда (и нужно ли) его утилизировать. Сможете ли вы уйти, не выбросив его? Вы выбрасываете его преждевременно и рискуете ObjectDisposedException? Это вопросы, на которые вам не нужно отвечать с помощью lock.

  6. Lock может выжить в сценарии прерванного потока. Он переводится компилятором C# так:

    bool lockTaken = false;
    try
    {
        Monitor.Enter(obj, ref lockTaken);
        DoBlockingStuff();
    }
    finally
    {
        if (lockTaken)
        {
            Monitor.Exit(obj);
        }
    }

Monitor.Enter был тщательно закодирован, поэтому в случае прерывания потока lockTaken будет иметь правильное значение. Напротив, SemaphoreSlim.Wait вызывается за пределами блока try/finally, поэтому есть небольшое окно, в котором текущий поток может быть прерван без снятия блокировки, что приводит к взаимоблокировке.

Платформа .NET прекратила поддержку метода Thread.Abort, так что можно с полным правом сказать, что последний пункт имеет только теоретическое значение.

Другие вопросы по теме