使用foreach时出现奇怪的lock()行为

4

所以,这不是我的代码,并且已经被缩短以展示其行为,但它给出了非常意外的结果。

我有一个类中的两个函数和一个锁。

object mylock = new object();
List<string> temp = new List<string>();

Func1(string)
{
  lock(mylock)
  {
    temp.Add(string);
  }
}

Func2()
{
  lock(mylock)
  {
    temp.ForEach(p => Func1(p));
  }
}

现在,我知道这没有意义,但是当调用Func2时,Func1不应该死锁吗?在我们的情况下,它会执行。谢谢。
3个回答

13

不会死锁。

如果Func1是被已经持有锁的线程(例如Func2)调用,它可以获取锁。

lock的MSDN文档解释道:

“当互斥锁被持有时,执行在同一执行线程中的代码也可以获得和释放锁。但是,在其他线程中执行的代码将被阻止直到锁被释放。”

锁的目的是防止不同线程访问相同资源。Func1Func2同一线程中。


func1肯定获取到了那个锁,因为我在调试器中逐步执行它。这个类实际上是一个单例(我知道,我知道...),所以我知道只有一个类的实例。我不明白发生了什么... - Steve
@Steve。没错,这就是我说的。Func1可以获取锁,因为它被Func2调用,而Func2拥有锁。 - Daniel LeCheminant

3
lock语句(封装了Monitor类)支持在线程内部进行重入(递归),即可以嵌套调用使用同一个监视器的调用。
其他加锁方法:
  • Monitor - 支持递归
  • ReaderWriterLock - 支持递归,但速度较慢
  • ReaderWriterLockSlim - 支持递归,但不建议使用
  • EventHandleManualResetEventAutoResetEventMutexSemaphore)- 不支持递归

1

.NET 监视对象(锁使用)是递归的,因此持有锁的线程可以自由地再次进入该锁。

(并非所有的锁定构造都是递归的,而且可以对递归支持提出异议。)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接