究竟是什么意思锁定一个对象?

时间:2010-01-01 09:00:19

标签: c# multithreading locking

Altough我在我的应用程序中使用锁,我不明白锁定特定引用类型到底是什么。我认为它只是停止线程,直到{}的内容完成。但我已经读过锁定(这个)很糟糕,如果是公开的 - 为什么?文章解释了它,但我不明白我不知道对象本身被锁定的情况。 例如,如果我使用lock(this)并从另一个线程调用其方法怎么办?我以为只有锁下的代码受到保护,否则我将无法访问被锁定的对象? 感谢

5 个答案:

答案 0 :(得分:8)

托管堆上的每个对象都可以用作锁对象,这是一种在线程之间同步访问的方法。

  

我认为它只会在{}的内容完成之前停止线程。

好吧,lock它阻止其他线程获取锁定,直到锁定被释放,这通常是在lock语句结束时(但它也可以是Monitor.Wait)。

lock(this)用法很危险,因为锁定很复杂,并且确切地了解哪些线程锁定哪个对象在哪个时间对于避免死锁非常重要;但是,如果您lock(this)您无法控制其他线程 - 这可能 (意外地)锁定同一个对象。使用private字段进行锁定会更安全。

例如,如果您(在同步列表中):

private IList<T> innerList = ...
public int Count { get { lock(this) { return innerList.Count; } } }

然后不难想象另一段代码引用这个同步列表并锁定它,例如:

SyncList<T> list = ...
lock(list) { // lock for atomicity
    if(!list.Contains(value)) list.Add(value);
}

这是一个潜在的僵局;如果Count lock(this),但锁定私人对象会更好,即

private readonly object syncLock = new object();
public int Count { get { lock(syncLock) { return innerList.Count; } } }

现在没有这个问题的风险。这里的另一个问题是,类似字段的事件和[MethodImpl]都会导致lock(this)。由于完全相同的原因,锁定Type(对于静态方法)同样危险。

答案 1 :(得分:7)

对象本身未锁定。将每个对象视为具有关联的锁(或监视器)。当一个线程获得锁定时,没有其他线程可以在没有第一个线程释放它的情况下获取它,通过调用Monitor.Exit(这是lock语句结束时发生的事情)或通过调用{ {1}}。调用Monitor.Wait获取锁的线程将阻塞,直到它可以获取锁。

对象本身根本不受“保护” - 锁定基本上是建议性的。

不锁定“this”的原因是你不知道其他代码对“this”的引用。获得正确的锁定需要您知道线程将在哪些情况下拥有锁定 - 并且您无法知道控制之外的代码是否可以取消锁定。例外情况是,如果您为了共享锁的明确目的而公开引用(例如.NET 1.1集合上的Monitor.Enter属性)。

答案 2 :(得分:1)

锁定一个对象对该对象本身没有任何作用 - 它只是意味着试图锁定同一个对象的任何其他线程将被停顿,直到锁定线程释放它为止。 锁定(this)不赞成的原因是对象外部的其他代码也可以锁定对象,从而干扰其正常操作。

答案 3 :(得分:1)

当你使用lock(someObject) { ...code... }时,它意味着只有一次线程可以在锁定区域内(假设你总是锁定同一个对象!)。尝试进入该区域的第二个线程将阻塞并且必须等到第一个线程离开。如果您在同一个对象上锁定了两个lock (someObject) { }区域,则只有一个线程可以进入任何这些区域。

锁定通常是一个保密的实现细节。锁定公共成员是一个坏主意,因为这意味着您的类的客户端也可以锁定此同一对象,并且可能导致死锁或不必要的减速。由于同样的原因,锁定this是不好的。

创建一个私有新对象并锁定它。

答案 4 :(得分:0)

using System;
        using System.Threading;
        class sycexp
                {
                public static void Main()
                        {
                        exp e=new exp();
                        Thread t1=new Thread(new ThreadStart(e.show));
                        Thread t2=new Thread(new ThreadStart(e.show));
                        t1.Name="First Thread";
                        t2.Name="Second Thread";
                        t1.Start();
                        t2.Start();
                        }
                 }
        class exp
                {
                public object lockme=new object();
                public void show()
                        {
                        lock(lockme)
                                {
                                Console.WriteLine("Start "+Thread.CurrentThread.Name.ToString());
                                Console.WriteLine("1");
                                Console.WriteLine("2");
                                Console.WriteLine("3");
                                Console.WriteLine("4");
                                Console.WriteLine("5");
                                Console.WriteLine(Thread.CurrentThread.Name.ToString()+" Stopped");
                                }
                        }
                 }