gpt4 book ai didi

c# - 当调用方法已经锁定同一对象时,尝试获取该对象的锁定

转载 作者:行者123 更新时间:2023-11-30 22:05:36 27 4
gpt4 key购买 nike

我有一些代码,我一直在研究这个系统,我遇到了一些对我来说有代码味道的代码,我认为它根本行不通,但它确实行得通。

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

private object lockObj = new object();

对象 B 将获取对象 A.lockObj 上的锁,而 B 拥有它调用的锁

A.SomeMethod();

A.SomeMethod() 获取锁

this.lockObj

并在代码中显示:

线程测试:

 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);
}
}

线程测试:

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)领域 - 我知道这是错误的,但代码中就是这样。
  2. 循环引用 - 我知道循环引用并且知道它为什么不好。

感谢您提供的任何见解。

最佳答案

您的印象似乎是 拥有一把锁(又名监视器)。事实并非如此 - 线程 拥有监视器。

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

来自 Monitor.Enter (lock 关键字调用的方法 - 它实际上调用了 TryEnter,但是...):

It is legal for the same thread to invoke Enter more than once without it blocking; however, an equal number of Exit calls must be invoked before other threads waiting on the object will unblock.

关于c# - 当调用方法已经锁定同一对象时,尝试获取该对象的锁定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24285743/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com