关于C#中的锁定对象

时间:2012-08-14 12:49:07

标签: c# object thread-safety locking

请考虑以下代码:

static void AddItem()
{
    lock (_list) 
        _list.Add ("Item " + _list.Count); //Lock 1

    string[] items;
    lock (_list) 
        items = _list.ToArray(); //Lock 2
    foreach (string s in items) 
        Console.WriteLine (s);
}

如果线程A获得锁定2,并且线程B尝试获得锁定1,那么B是否会获得锁定?考虑两个锁都使用相同的锁定对象。

5 个答案:

答案 0 :(得分:5)

不,线程B需要等到线程A释放锁定。这就是它是同一个锁对象的重点 - 毕竟还有一个锁。获取或释放锁定无关紧要:一次只能有一个线程“拥有”监视器。

顺便说一句,我会强烈建议你使用大括号来提高可读性:

lock(_list)
{
    _list.Add(...);
}

答案 1 :(得分:2)

不,因为它们使用相同的锁定对象,所以它们是互斥的。

通常,代码用于锁定对象(例如列表)以对其执行操作,而不会受到其他线程的干扰。这要求无论执行什么操作,项目都会被锁定。

详细说明,假设您有一个设计为线程安全的列表。如果您尝试同时添加和删除多个项目,则可能会损坏列表。通过在需要修改时锁定列表,可以帮助确保线程安全。

这一切都取决于一个对象将使所有锁互斥。

答案 2 :(得分:2)

不,B不会。两者都锁定在同一个对象上,因此两个锁是“链接的”。因此,如果您需要高度优化此类代码,有时您可能会考虑多个锁定对象。

作为旁注,您不应该锁定列表本身,而应该锁定在专门为此目的创建的object上。

答案 3 :(得分:1)

如果线程A正在使用锁,那么没有其他线程可以使用它(无论锁在何处使用)。因此,线程B将被阻止,直到该锁定为空。

答案 4 :(得分:1)

考虑一下:

lock(obj)
{
 //Do Stuff;
}

简写:

Monitor.Enter(obj);
try
{
  //Do Stuff;
}
finally
{
  Monitor.Exit(obj);
}

现在考虑Monitor.Enter()是一个方法调用,就像任何其他方法一样。它对所调用的代码中的位置一无所知。它唯一知道的是传递给它的对象。

就你而言,你所谓的“锁1”和“锁2”是同一个锁。