我有这个C#代码:
public class Locking
{
private int Value1; private int Value2;
private object lockValue = new Object();
public int GetInt1(int value1, int value2)
{
lock (lockValue)
{
Value1 = value1;
Value2 = value2;
return GetResult();
}
}
public int GetInt2(int value1, int value2)
{
lock (lockValue)
{
return GetInt1(value1, value2);
}
}
private int GetResult()
{
return Value1 + Value2;
}
}
所以基本上我期望一个死锁,如果我执行GetInt2但代码只是执行.任何好的解释.
解决方法:
这里的一般情况是同步对象是否可重入.换句话说,如果已经拥有锁,则可以通过相同的线程再次获取.另一种说法是对象是否具有“线程亲和力”.
在.NET中,Monitor类(实现lock语句),Mutex和ReaderWriterLock是可重入的. Semaphore和SemaphoreSlim类不是,您可以使用二进制信号量使代码死锁.实现锁定的最便宜的方法是使用Interlocked.CompareExchange(),它也不会重入.
使同步对象可重入需要额外的成本,它需要跟踪哪个线程拥有它以及在拥有线程上获取锁的频率.这需要存储Thread.ManagedId和一个计数器,两个整数.这影响了C中的选择,例如,C 11语言规范最终将线程添加到标准库. std :: mutex类在该语言中不可重入,并且拒绝添加递归版本的提议.他们考虑了使其重入过高的开销.也许有点笨手笨脚,花费在调试意外死锁上花费的时间相当微不足道的成本:)但它是一种语言,它不是灌篮,获得线程ID可以保证像它一样便宜.净.
这在ReaderWriterLockSlim类中公开,您可以选择.请注意RecursionPolicy属性,允许您在NoRecursion和SupportsRecursion之间进行选择. NoRecursion模式更便宜,而且非常纤薄.