C#正确锁定

时间:2015-03-07 23:13:12

标签: c# multithreading parallel-processing locking

假设我已执行此类操作:

A.B.C.add(new D());
A.B.add(new C));
A.add(new B));

这些操作同时执行 。想象一下,这些方法有三种不同的方法。

lock(A.B.C)
   A.B.C.add(new D());

lock(A.B)
   A.B.add(new C));

lock(A)
   A.add(new B));

这些锁是否独立?换句话说 - 这些行动是在同一时间执行,还是仅在前一个行动完成后才执行?

如果它是正确的 - 它是设置锁定的最有效方法吗?

修改

我有很多这种类型的调用(这3种方法被多次调用)。

2 个答案:

答案 0 :(得分:0)

是的,锁是彼此独立的。 lock语句实际上在参数实例上创建了一个监视器,它没有考虑到你实际到达那里的方式(即属性链A.B.C)。

但是,您的代码存在一个微妙的问题。由于锁是独立的,并且三个锁语句可以同时执行,所以任何语句都可以是

lock(A.B.C)
    A.B.C.Add(new D());

是危险的,因为当获得锁定时,属性A.B.C可能已经改变。因此,为此使用局部变量会更好(即更安全):

var c = A.B.C;
lock(c)
    c.Add(new D());

答案 1 :(得分:0)

这些陈述将同时进行。您可以通过运行以下代码并看到控制台全部立即写入来测试这一点:

Task.Run(() =>
{
    lock (a.B.C)
    {
        Console.WriteLine("a.B.C");
        Thread.Sleep(5000);
    }
});

Task.Run(() =>
{
    lock (a.B)
    {
        Console.WriteLine("a.B");
        Thread.Sleep(5000);
    }
});

Task.Run(() =>
{
    lock (a)
    {
        Console.WriteLine("a");
        Thread.Sleep(5000);
    }
});

来自C# reference

  

最佳做法是定义要锁定的私有对象

所以在这种情况下的内容如下:

public class A
{
    private readonly object _syncLock = new object();
    public B B { get; private set; }

    public A()
    {
    }

    public void Add(B b)
    {
        lock (_syncLock)
        {
            // The actual logic
        }
    } 
}

这样,线程安全性由Add方法本身处理,因此不需要考虑外部调用。