C#Lock语法 - 2个问题

Ere*_*rez 3 .net c# multithreading locking

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

lock("something")
Run Code Online (Sandbox Code Playgroud)

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

lock("something") foo();
Run Code Online (Sandbox Code Playgroud)

Geo*_*ett 10

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

你应该做这个:

private static readonly object mutex = new object();

lock(mutex)
{
    //....
}
Run Code Online (Sandbox Code Playgroud)

2)是的,与所有陈述相同.你有的地方*:

{
    // One line
}
Run Code Online (Sandbox Code Playgroud)

可能只是

// One line
Run Code Online (Sandbox Code Playgroud)

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


Bri*_*eon 6

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

案例1: Literal vs. StringBuilder

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

string a = "something";
string b = new StringBuilder().Append("some").Append("thing").ToString();

// These are different.
lock (a)
lock (b)
Run Code Online (Sandbox Code Playgroud)

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

// These are the same.
lock (a)
lock (String.Intern(b))
Run Code Online (Sandbox Code Playgroud)

案例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))
Run Code Online (Sandbox Code Playgroud)

案例3:实施差异

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

案例4: CompilationRelaxations.NoStringInterning

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


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

  • 简短的回答:不要锁定字符串. (2认同)