为什么此代码不会以死锁结束 [英] Why does this code not end in a deadlock

查看:85
本文介绍了为什么此代码不会以死锁结束的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下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时出现死锁,但是代码只会执行.任何好的解释.

So basically I expect a deadlock if I execute GetInt2 but the code just executes. Any good explanation.

推荐答案

此处的一般情况是同步对象是否为可重入.换句话说,如果相同的线程已经拥有该锁,则可以再次获取它.换句话说,该对象是否具有线程相似性".

The general case here is whether or not a synchronization object is re-entrant. In other words, can be acquired again by the same thread if it already owns the lock. Another way to say that is whether the object has "thread affinity".

在.NET中,Monitor类(实现lock语句),Mutex和ReaderWriterLock是可重入的. Semaphore和SemaphoreSlim类不是 类,您可以使用二进制信号量使代码陷入僵局.实现锁定的最便宜的方法是使用Interlocked.CompareExchange(),它也不会重新进入.

In .NET, the Monitor class (which implements the lock statement), Mutex and ReaderWriterLock are re-entrant. The Semaphore and SemaphoreSlim classes are not, you could get your code to deadlock with a binary semaphore. The cheapest way to implement locking is with Interlocked.CompareExchange(), it would also not be re-entrant.

重新进入同步对象会带来额外的成本,它需要跟踪哪个线程拥有它,以及在拥有的线程上获得锁的频率.这需要存储Thread.ManagedId和一个计数器(两个整数).这影响了C ++中的选择,例如,C ++ 11语言规范最终将线程添加到了标准库中. std :: mutex类在该语言中是 not 不可重入的,添加递归版本的建议被拒绝.他们认为使其重入的开销过高.也许是有点笨拙,相对于调试意外死锁所花费的时间而言,这笔费用是微不足道的:)但是,在这种语言中,毫无疑问,获取线程ID可以像在in中那样便宜是明智的. NET.

There is an extra cost associated with making a sync object re-entrant, it needs to keep track of which thread owns it and how often the lock was acquired on the owning thread. Which requires storing Thread.ManagedId and a counter, two ints. This affected choices in C++ for example, the C++11 language specification finally adding threading to the standard library. The std::mutex class is not re-entrant in that language and proposals to add a recursive version were rejected. They considered the overhead of making it re-entrant too high. A bit heavy-handed perhaps, a cost that's rather miniscule against the amount of time spent on debugging accidental deadlock :) But it is a language where it is no slamdunk that acquiring the thread ID can be guaranteed to be cheap like it is in .NET.

这在ReaderWriterLockSlim类中公开,您可以选择.请注意RecursionPolicy属性,使您可以在NoRecursion和SupportsRecursion之间进行选择. NoRecursion模式更便宜,并且使其真正 slim .

This is exposed in the ReaderWriterLockSlim class, you get to choose. Note the RecursionPolicy property, allowing you to choose between NoRecursion and SupportsRecursion. The NoRecursion mode is cheaper and makes it truly slim.

这篇关于为什么此代码不会以死锁结束的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆