决定锁定特定对象的任何指导

Any guidance of deciding a particular object for locking

我见过几种将特定对象用于锁构造的不同方法。

  1. 有一个专用的私有静态局部变量并锁定它

    private static object syncObj = new object();  
    ...  
    lock(syncObj)  
    {
    
    }
    
  2. 有一个专用的私有局部变量并锁定它

    private object syncObj = new object();  
    ...  
    lock(syncObj)  
    {
    
    }
    
  3. 另一种是使用对象本身。

    private List<MyClass> SomeObjects = new List<MyClass>();  
    ....  
    lock(SomeObjects)  
    {  
    
    }
    
  4. 一种方法是使用特定对象的类型。

    private List<MyClass> SomeObjects = new List<MyClass>();  
     ...    
    lock(SomeObjects.GetType())  
    {  
    
    }
    
  5. 另一种可能性是使用 lock(this) 但一般建议似乎尽量避免使用它。

我的问题。
1. 对象加锁还有其他方法吗?
2. 我如何决定针对特定场景应该使用哪种方法?

如果 Marc Gravell 对 C# lock statement, what object to lock on? 的回答是最高投票-getter(恕我直言,它应该是),我很乐意投票将这个问题作为重复问题关闭。

但是,事实并非如此。这个问题在上下文中确实有一些细微的差异。所以……

特别以你的五个例子为例:

  1. Have a dedicated private static local variable and lock on that

这适用于您有一些需要同步的静态成员的情况。 .NET 中的一个常见实现约定是使所有静态成员线程安全,并且对于本身不是专门针对多线程代码的类型,不要费心使实例成员线程安全。

注意声明应该是static readonly,以确保锁定对象在程序的整个生命周期中保持不变。

  1. Have a dedicated private local variable and lock on that

这对于保护实例成员更好,在 class 中特别应该是线程安全的。虽然 static 锁对象也可以工作,但这可能会引起不必要的争议。也就是说,私有实例成员通常不会受到接触它们的对象的其他实例的影响,因为 classes 通常只对它们自己的实例成员进行操作,而不是其他实例的实例成员。

A static 锁对象将要求在 any 实例上操作的所有线程同步它们的执行,这对于使用不同实例的线程并发操作是安全的。

static 锁定对象一样,使字段 readonly.

  1. Another one is to use the object itself.

我倾向于尽量避免这样做。如果该对象是私有维护的,并且您确定除了您自己的代码和对象本身之外的任何其他代码都不知道该引用,那么它就足够安全了。但这可能有风险,因为您无法确定即使该对象当前从未在其他地方使用过,代码也永远不会更改,以便以后使用。

如果引用在您自己的 class 之外变得可用,那么其他一些代码也可能以不合时宜的方式锁定对象。最糟糕的情况是,如果它获得了其他一些锁,然后试图锁定该对象,而您自己的代码试图获得已经锁定该对象的其他锁。僵局。不太坏的只是增加锁上的线程争用。该代码仍然有效,但也可能 运行 无效。

  1. One approach is to use the type of a particular object

这结合了以上最差的:公开可用的参考、静态成员。强烈建议反对

  1. Another possibility is using lock(this) but general recommendation seem to try to avoid using this.

这只是 #3 的一个变体,除了您实际上可以保证该引用将被其他代码使用。不建议。


在 "it is possible" 的意义上,您可以使用带有 lock 语句的任何引用(即任何 class 值……您绝对 不应该使用 任何struct 值,正如普雷斯顿建议的问题的答案中所建议的那样)。但是,有很多方法可以解决这个问题。

恕我直言,最好的策略是保持简单:匹配 static/instance 声明你试图保护的任何东西(整个对象,或者在某些情况下对特定对象的特定操作), 始终使字段 readonly, 并完成它。