在一个方法中锁定某个对象是否也使其锁定在其他方法中?

时间:2012-06-04 12:57:00

标签: c# multithreading locking

当某个线程在myList中锁定SomeMethodA并执行lock内的块时,其他线程是否可以在myList.Add(1)中执行SomeMethodB或者它将等待因为'myList'被锁定在SomeMethodA

class A
{
    private List<int> myList;

    public void SomeMethodA()
    {
       lock(myList)
       {
          //...
       }
    }

    public void SomeMethodB()
    {
       myList.Add(1);
    }
}

4 个答案:

答案 0 :(得分:6)

修改明确答案:,您需要在SomeMethodB中明确锁定列表。编译器不会自动为您添加锁

  • 为什么你必须明确锁定否则?
  • 事情会非常缓慢。禁止多线程比总是锁定每个对象访问 1
  • 要好得多

推荐的习语是:

class A
{
    private List<int> myList;
    private readonly object _lockObject = new Object();

    public void SomeMethodA()
    {
       lock(_lockObject)
       {
          //...
       }
    }

    public void SomeMethodB()
    {
       lock(_lockObject)
       {
           myList.Add(1);
       }
    }
}

小心暴露像这样的细粒度锁定(只要在锁定下不会发生阻塞操作,您通常希望进行粗粒度锁定。)

注意但是,C#中的锁是可重入的,因此从SomeMethodB中的锁内调用SomeMethodA不会死锁

更新使用私有锁object实例背后的原理:

  

通常,避免锁定公共类型或超出代码控制范围的实例。常见的构造锁(this),lock(typeof(MyType))和lock(“myLock”)违反了这条准则:

     
      如果可以公开访问实例,则
  • lock (this)会出现问题。
  •   如果lock (typeof (MyType))可公开访问,则
  • MyType会出现问题。
  •   
  • lock("myLock")是一个问题,因为使用相同字符串的进程中的任何其他代码都将共享相同的锁。
  •   
     

最佳做法是定义要锁定的私有对象,或私有静态对象变量以保护所有实例共有的数据。

请参阅:http://msdn.microsoft.com/en-us/library/c5kehkcz.aspx


1 (除了该方法的其他问题,例如空值,参考更新,死锁等)。

答案 1 :(得分:2)

锁定对象会在应用程序中全局锁定它。您甚至可以在其他类中观察锁定(如果您锁定了公共对象)。

但是,在您的示例代码中,myList.Add(1)等待锁定,因为您尚未将其包装在lock块中。

当我们说“锁定对象”或“获取对象锁定”时,它有点用词不当,因为lock语句实际上没有要做的任何事情以防止访问对象。相反,它通过使用该对象作为“密钥”来防止多个线程进入锁定的代码块 - 并且一次只有一个线程可以拥有该密钥。因此,当您“锁定”一个对象时,所有线程仍可以自由使用该对象,但一次只有一个线程可以使用该对象进入lock块。

答案 2 :(得分:1)

答案是否。一旦一个线程获得了对某个对象的锁(在你的情况下为myList),没有其他线程可以访问该对象的锁,Thread1将阻塞所有其他线程,直到Thread1释放myList的锁,但是条件是如果其他线程也在尝试锁定。

在您的示例中,如果Thread1正在执行SomeMethodA()(其锁定为myList)且Thread2正在执行SomeMethodB()(其中它不请求锁定),那里不会有任何问题,他们不会互相阻挡

请考虑以下示例以获得更多说明。

class A
{
    private List<int> myList;

    public void SomeMethodA()
    {
       lock (myList)
       {
           //...
       }
    }

    public void SomeMethodB()
    {
        myList.Add(1);
    }

    public void SomeMethodC()
    {
        lock (myList)
        {
            myList.Add(2);
        }
    }
}

Thread1正在尝试访问SomeMethodA()

Thread2正在尝试访问SomeMethodB()

Thread3正在尝试访问SomeMethodC()

Thread1和Thread2将在不阻塞的情况下执行,但Thread3将在myList锁定时被阻止,因为Thread1已经获取了它。

答案 3 :(得分:0)

如果你没有在SomeMethodB内置锁,即使你在SomeMethodA的锁中执行了一个线程,所有线程都可以访问它。为了防止线程运行SomeMethodB,您需要像sehe一样实现您的方法。