可能重复:
C#中的重入锁定
如果我写这样的代码:
class Program {
static void Main(string[] args) {
Foo();
Console.ReadLine();
}
static void Foo() {
lock(_lock) {
Console.WriteLine("Foo");
Bar();
}
}
static void Bar() {
lock(_lock) {
Console.WriteLine("Bar");
}
}
private static readonly object _lock = new object();
}
Run Code Online (Sandbox Code Playgroud)
我得到输出:
Foo
Bar
Run Code Online (Sandbox Code Playgroud)
我预计这会陷入僵局,因为Foo获得了一个锁,然后等待Bar获得锁.但这不会发生.
锁定机制是否只允许这个,因为代码是在同一个线程上执行的?
我读了一些关于SyncRoot模式的内容,作为避免死锁的一般规则.阅读几年前的问题(见此链接),我想我明白这种模式的一些用法可能是不正确的.特别是,我专注于本主题的以下句子:
您会注意到System.Collections中许多集合上的SyncRoot属性.在回顾中,我认为这个属性是一个错误......请放心,我们不会犯这个错误,因为我们构建这些集合的通用版本.
实际上,例如,List<T>类不实现SyncRoot属性,或者更正确地实现它是显式实现的(请参阅此答案),因此必须强制转换ICollection才能使用它.但是这篇评论认为,SyncRoot公开私人领域与锁定一样糟糕this(见这个答案),这也在本评论中得到证实.
因此,如果我理解正确,当我实现非线程安全的数据结构时,因为它可以在多线程上下文中使用,所以我不应该(实际上,我不能)提供该SyncRoot属性.但是我应该让开发人员(将使用此数据结构)的任务是将其与私有SyncRoot对象相关联,如下面的示例代码所示.
public class A
{
private MyNonThreadSafeDataStructure list;
private readonly object list_SyncRoot = new object;
public Method1()
{
lock(list_SyncRoot)
{
// access to "list" private field
}
}
public Method2()
{
lock(list_SyncRoot)
{
// access to "list" private field
}
}
}
Run Code Online (Sandbox Code Playgroud)
总之,我了解同步/锁定的最佳实践应如下所示:
我试图理解ICollection中syncroot的意义.为什么不直接锁定集合?
lock(myCollection)
{
//do stuff to myCollection
}
Run Code Online (Sandbox Code Playgroud)
VS
lock(myCollection.SyncRoot)
{
//do stuff to myCollection
}
Run Code Online (Sandbox Code Playgroud)