当调用方法已锁定同一对象时,尝试获取对象的锁定

时间:2014-06-18 12:33:56

标签: c# multithreading locking

我有一些代码,我一直在学习系统,我遇到了一些代码,对我来说是一个代码味道,我认为它根本不会起作用,但确实如此。

我们有两个对象,对象A和对象B。对象A包含一个锁对象:

private object lockObj = new object();

对象B将获取对象A.lockObj的锁定,而B具有其调用的锁定

A.SomeMethod();

A.SomeMethod()获得锁定

this.lockObj

并在代码中显示:

ThreadTestOne:

 public class ThreadTestOne
{
    public object lockObject = new object();

    private List<string> lst;

    private ThreadTestTwo two;

    public List<string> Lst
    {
        get
        {
            return this.lst;
        }
        set
        {
            this.lst = value;
        }
    }

    public void Run()
    {
        lst = new List<string>();
        two = new ThreadTestTwo();
        two.Run(this);
    }

    public void End()
    {
        Console.WriteLine("ThreadTestOne.End");
        two.End();
    }

    public void LockMe()
    {
        Console.WriteLine("ThreadTestOne.LockMe");
        lock (this.lockObject)
            lst.Add("something");
            Thread.Sleep(500);
    }
}

ThreadTestTwo:

public class ThreadTestTwo
{
    private ThreadTestOne one;
    private Thread myThread;
    private bool ending = false;

    public void Run(ThreadTestOne a)
    {
        one = a;
        myThread = new Thread(new ThreadStart(Consume));
        Console.WriteLine("ThreadTestTwo Starting thread");
        myThread.Start();
    }

    public void End()
    {
        Console.WriteLine("ThreadTestTwo.End");
        ending = true;
        myThread.Join();
    }

    public void Consume()
    {
        while (!ending)
        {
            Console.WriteLine("ThreadTestTwo one.lockObject");
            lock (one.lockObject)
            {
                Console.WriteLine("two.LockMe");
                one.LockMe();
                one.Lst.Add("two");
                Thread.Sleep(500);
            }
        }
    }
}

当我查看上面的代码时,我认为它应该会中断,因为one.LockMe()永远无法锁定lockObj因为ThreadTestTwo已经拥有锁定。

我认为这会导致死锁。但是,当我运行上面的示例代码时,它的工作原理。此外,我正在审查的代码也有效,目前正在制作中。

这不会导致抛出异常的事实让我感到困惑。假设这应该是错误,我是不正确的?

在我最初测试的代码中,只是在尝试获取锁定两次后才读取数据,所以我以为编译器正在删除锁定。

然而,我查看了MSIL并看到锁仍在那里。

我的下一个想法是框架只是没有获取锁,因为我们只是在阅读数据。

我在锁中添加了一个写操作,它仍然有效。但是,我可能无法完全理解锁定工作的方式。

尽管这有效,但我觉得这是错误的,我并不完全相信这不会导致生产问题。

我确实发现了这个问题:

use the same lock object at two different code block?

哪个相似,但我相信我的问题略有不同,我问的是当调用方法已经锁定同一个对象时锁定一个对象。

显然代码我对作品有疑问,我想知道怎么做?

我认为这是错误的吗?

上面的代码中我注意到了一些问题。

  1. public field - 我知道这是错的,但这就是代码中的情况。
  2. 循环引用 - 我知道循环引用并知道它为什么不好。
  3. 感谢您提供的任何见解。

1 个答案:

答案 0 :(得分:3)

您似乎认为拥有锁(又称监视器)。情况并非如此 - 线程拥有一台监视器。

.NET中的监视器是可重入的 - 如果一个线程已经拥有监视器,它可以再次获取它。这将增加它的“锁定计数” - 当线程第一次释放监视器时,它只会减少锁定计数,但由于计数仍然是正数,因此没有其他线程可以获取监视器,直到原始线程再次发布

来自Monitor.Enterlock关键字排序调用的方法 - 实际上调用TryEnter,但是......):

  

同一个线程在没有阻塞的情况下不止一次调用Enter是合法的;但是,在等待对象的其他线程将解除阻塞之前,必须调用相同数量的Exit调用。