c#锁定传递给方法的引用 – 不好的做法?

我有一个类似的方法:

public static void DoSomething (string param1, string param2, SomeObject o) { //..... lock(o) { o.Things.Add(param1); o.Update(); // etc.... } } 

几点:

  1. 用这种方式锁定不好的做法?
  2. 我应该锁定private static object吗?
  3. 如果是这样,为什么?

为了最大限度地减少副作用,被锁定的对象不应该是被操纵的对象,而应该是指定用于锁定的单独对象。

根据您的要求,有几个选项可以解决此问题:

变体A:私人锁定对象

如果您只想确保DoSomething不与DoSomething的并行实例冲突,请选择此选项。

 private static readonly object doSomethingLock = new object(); public static void DoSomething (string param1, string param2, SomeObject o) { //..... lock(doSomethingLock) { o.Things.Add(param1); o.Update(); // etc.... } } 

变体B:将锁定对象作为参数传递

如果访问o必须在DoSomething之外是线程安全的,那么选择此选项,即,如果存在其他人编写与DoSomethingElse并行运行且不得干扰DoSomethinglock块的方法DoSomethingElse的可能性:

 public static void DoSomething (string param1, string param2, SomeObject o, object someObjectLock) { //..... lock(someObjectLock) { o.Things.Add(param1); o.Update(); // etc.... } } 

变体C:创建SyncRoot属性

如果您可以控制SomeObject的实现,则可以方便地将锁定对象作为属性提供。 这样,您可以实现Variant B而无需传递第二个参数:

 class SomeObject { private readonly object syncRoot = new object(); public object SyncRoot { get { return syncRoot; } } ... } 

然后,您只需在DoSomething使用lock(o.SyncRoot) 。 这是一些BCL类使用的模式,例如, Array.SyncLock , ICollection.SyncRoot 。

只是回答你的第三个问题:

想象一下,后者你决定锁定另一个方法参数,可能是这样的:

 public void XXX(object o) { lock(o) { } } 

您将很难尝试查看是否存在死锁。 您将需要检查作为参数传递给SomeObject的对象是否永远不会作为参数传递给对象o。

这是一个关于如何使用锁的示例:

 class Account { decimal balance; private Object thisLock = new Object(); public void Withdraw(decimal amount) { lock (thisLock) { if (amount > balance) { throw new Exception("Insufficient funds"); } balance -= amount; } } } 

这意味着您锁定一个私有变量的Object,仅用于锁定而不是其他任何东西,

你可以看看这个:

lock语句(C#参考)

线程同步(C#和Visual Basic)