使用“lock”相对于“SemaphoreSlim”有什么优势?

问题描述 投票:0回答:1

我参加聚会迟到了,但我最近了解到了

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
?如果有,它们是什么?

c# multithreading thread-safety locking semaphore
1个回答
14
投票

以下是

lock
相对于
SemaphoreSlim
的优点:

  1. lock
    是可重入的,而
    SemaphoreSlim
    则不是。因此,使用
    lock
    进行编程更加宽容。如果您的应用程序中存在罕见的路径,您两次获取相同的锁,则
    lock
    将成功获取它,而
    SemaphoreSlim
    将死锁。

  2. lock
    是围绕
    Monitor
    类的语法糖。换句话说,C# 中有对
    Monitor
    的语言支持,但没有对
    SemaphoreSlim
    的语言支持。所以使用
    lock
    相对来说更方便,也更简洁。

  3. 您可以使用

    lock
    编写更健壮的代码,因为您可以在辅助方法中添加调试断言,表明锁定已获取
    Debug.Assert(Monitor.IsEntered(_locker));

  4. 您可以使用

    Monitor.LockContentionCount
    属性获取争用统计信息: “获取尝试获取监视器锁定时发生争用的次数。”
    SemaphoreSlim
    类没有可用的统计信息。

  5. SemaphoreSlim
    IDisposable
    ,所以你必须考虑何时(以及是否)处置它。你能不扔掉就离开吗?您是否过早地丢弃它并冒着
    ObjectDisposedException
    的风险?这些问题您不必用
    lock
    来回答。

  6. lock
    可以在线程中止的情况下生存。它是由 C# 编译器翻译的 like this:

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

Monitor.Enter
已仔细编码,以便万一线程中止,
lockTaken
将具有正确的值。相反,
SemaphoreSlim.Wait
通常在
try
/
finally
块之外调用,因此存在一个小窗口,可以在不释放锁的情况下中止当前线程,从而导致死锁。

.NET Core/5+ 平台已放弃对

Thread.Abort
方法的支持,因此您可以正确地说最后一点仅具有理论价值。

© www.soinside.com 2019 - 2024. All rights reserved.