Evo*_*lor 8 c# multithreading semaphore locking thread-safety
我参加聚会迟到了,但我最近了解到SemaphoreSlim:
我曾经用于lock同步锁定,并使用busy布尔值用于异步锁定。现在我SemaphoreSlim什么都用。
private SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1);
private void DoStuff()
{
semaphoreSlim.Wait();
try
{
DoBlockingStuff();
}
finally
{
semaphoreSlim.Release();
}
}
Run Code Online (Sandbox Code Playgroud)
与
private object locker = new object();
private void DoStuff()
{
lock(locker)
{
DoBlockingStuff();
}
}
Run Code Online (Sandbox Code Playgroud)
是否存在我应该更喜欢使用lockover 的同步情况SemaphoreSlim?如果有,它们是什么?
The*_*ias 16
lock以下是与 相比的优点SemaphoreSlim:
是lock可重入的,而SemaphoreSlim不是。因此使用 进行编程lock更加宽容。如果您的应用程序中存在罕见的路径,您两次获取相同的锁,则将lock成功获取它,而SemaphoreSlim将死锁。
这lock是类周围的语法糖Monitor。换句话说,MonitorC# 中有语言支持,而SemaphoreSlim. 所以使用起来lock相对来说更方便,也更简洁。
您可以使用 编写更健壮的代码,因为您可以在已获取lock锁的辅助方法中添加调试断言:Debug.Assert(Monitor.IsEntered(_locker));
您可以使用以下属性获取争用统计信息Monitor.LockContentionCount:“获取尝试获取监视器锁时发生争用的次数。” 该班级没有可用的统计数据SemaphoreSlim。
是SemaphoreSlim的IDisposable,所以你必须考虑何时(以及是否)处置它。你能不扔掉它就走吗?您是否过早地处置它并冒着风险ObjectDisposedException?这些问题您不必用 来回答lock。
lock在线程中止的情况下,它们可以生存。它由 C# 编译器翻译如下:
bool lockTaken = false;
try
{
Monitor.Enter(obj, ref lockTaken);
DoBlockingStuff();
}
finally
{
if (lockTaken)
{
Monitor.Exit(obj);
}
}
Run Code Online (Sandbox Code Playgroud)
已Monitor.Enter仔细编码,以便万一线程中止,将lockTaken具有正确的值。相反,通常在/块SemaphoreSlim.Wait之外调用,因此存在一个小窗口,可以在不释放锁的情况下中止当前线程,从而导致死锁。tryfinally
.NET Core/5+ 平台已放弃对该Thread.Abort方法的支持,因此您可以正确地说最后一点仅具有理论价值。