【发布时间】:2011-08-04 06:55:30
【问题描述】:
我可以在锁中使用字符串作为储物柜吗?
lock("something")
如果只有一行,我可以不加括号吗?
lock("something") foo();
【问题讨论】:
标签: c# .net multithreading locking
我可以在锁中使用字符串作为储物柜吗?
lock("something")
如果只有一行,我可以不加括号吗?
lock("something") foo();
【问题讨论】:
标签: c# .net multithreading locking
1) 是的,字符串(通常)被保留(默认情况下,感谢@Eric),因此相同"something" 的任何实例都将指向同一个对象,因此您将好的。 这是非常不好的做法,因为其他人,例如在另一个库中,可能会锁定您的字符串,从而可能导致死锁。请参阅此处:Using string as a lock to do thread synchronization
你应该这样做:
private static readonly object mutex = new object();
lock(mutex)
{
//....
}
2) 是的,与所有语句相同。您拥有的任何东西*:
{
// One line
}
可能是
// One line
*几乎任何东西,参见@LukeH 的catch 块示例,它需要大括号。
【讨论】:
try ... catch 必须拥有它们,即使是单线。是的,您可以使用字符串实例作为锁定的目标。但是,有一些非常奇怪的边缘情况需要考虑。
案例 1: Literal vs. StringBuilder
在以下示例中,两个锁不会使用相同的字符串实例。这是因为字面量是 inned,但构建的实例不是。
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: 实施差异
Microsoft 的 CLI 实施并不是唯一的。可以想象,不同的实现会表现出不同的行为并有自己的一套注意事项。
案例 4: CompilationRelaxations.NoStringInterning
取决于程序集是否用 this 修饰以及 CLR 是否实际使用它(而不是忽略它)可能会改变实习机制的行为。这是一个特别有害的问题,因为它可能意味着同一代码的行为会根据其运行的上下文而有所不同。
我确信还有其他我不知道的极端情况。然而,关键是依赖字符串实例来实现锁定目的(或任何需要隐含假设其引用等价的目的)是危险的。
【讨论】:
乔治所写的一切都是正确的。一个补充虽然。无论如何,您都应该使用大括号来完全清楚您想要在大括号内运行什么。假设你不小心写了这样的东西:
if(...)
// one line
// another line
当您阅读时,您可能会认为这两行都将在 if 块内执行(一些示例使用标识来定义块)。如果你改为写
if(...)
{
// one line
}
// another line
很清楚什么在 if 块中运行,什么不是。
【讨论】: