C#Lock语法 – 2个问题

我可以在锁中使用字符串作为锁定器吗?

lock("something") 

如果它只有一条线,我可以不用括号锁定吗?

 lock("something") foo(); 

1)是的,字符串(通常)被实习( 默认情况下 ,感谢@Eric),因此任何相同"something"实例都会指向同一个对象,因此你就可以了。 这是非常糟糕的做法,因为其他人,例如,在另一个库中,可能会锁定您的字符串,从而可能导致死锁。 请参见此处: 使用字符串作为锁来执行线程同步

你应该做这个:

 private static readonly object mutex = new object(); lock(mutex) { //.... } 

2)是的,与所有陈述相同。 你有什么地方:

 { // One line } 

可能只是

 // One line 

*几乎任何东西,请参阅@LukeH的catch块示例,它需要括号。

是的,您可以使用字符串实例作为锁的目标。 但是,有一些非常奇怪的边缘情况需要考虑。

案例1: Literal vs. StringBuilder

在以下示例中,两个锁将不使用相同的字符串实例。 这是因为文本是实际的,但是构建的实例不是。

 string a = "something"; string b = new StringBuilder().Append("some").Append("thing").ToString(); // These are different. lock (a) lock (b) 

但是,我们可以手动实习字符串。

 // These are the same. lock (a) lock (String.Intern(b)) 

案例2:版本考虑因素

空字符串从版本到版本的实现方式存在一些差异。

 string a = String.Empty; string b = new StringBuilder().Append(String.Empty); // These are the same in 1.0, 1.1, 3.5, and 4.0. // These are different in 2.0 and 3.0. lock (a); lock (String.Intern(b)) 

案例3:实施差异

微软的CLI实现并不是唯一的。 可以想象,不同的实现表现出不同的行为并且具有它们自己的一组警告。

案例4: CompilationRelaxations.NoStringInterning

根据组件是否用此装饰以及CLR是否实际使用它(而不是忽略它)可能会改变实习机制的行为。 这是一个特别有害的问题,因为它可能意味着相同的代码根据其运行的上下文而表现不同。


我确信还有其他边缘情况我不知道。 但是,重点是依赖字符串实例进行锁定(或任何需要隐式假设其引用等价的目的)是危险的。

乔治写的一切都是正确的。 但有一个补充。 无论如何你应该使用大括号来完全清楚你想要在大括号内运行什么。 让你偶然写下类似的东西:

 if(...) // one line // another line 

在读取时你可能会在if块中执行这两行(某些示例使用identation来定义块)。 如果你反而写

 if(...) { // one line } // another line 

很清楚if块中运行的是什么,什么不是。