我遇到锁定声明上的问题困扰我:
如果连接两个具有相同表达式(noexcept
)的字符串,如下所示,lock语句将此表达式实现为字符串并按预期锁定工作:
"1" + "2"
但是,如果使用lock ("1" + "2")
{
Task.Factory.StartNew(() =>
{
lock ("1" + "2")
{//launched afetr 10 second
}
});
Thread.Sleep(10000);
}
lock ("1" + "2")
虽然两个表达式具有相同的结果,但是锁定语句句柄与此作为两个不同的表达式,因此第二个锁定语句立即启动:
var a="1"; lock (a + "2")
请解释一下这种行为:
(我知道在锁定语句中使用字符串(MSDN)违反了锁定准则。)
答案 0 :(得分:0)
如果代码更改为:
lock ("1" + "2")
{
Console.WriteLine("outer lock");
Task.Factory.StartNew(() =>
{
lock ("12")
{//launched afetr 10 second
Console.WriteLine("inner lock");
}
});
Thread.Sleep(10000);
}
然后"内锁"将在" outter lock"。
之后10秒打印这意味着" 1" +" 2"字面上等于" 12"。
但是,如果使用.NET Reflector打开IL代码:
lock ("1" + "2")
{
Console.WriteLine("outer lock");
Task.Factory.StartNew(() =>
{
var a = "1";
lock (a + "2")
{//launched afetr 10 second
Console.WriteLine("inner lock");
}
});
Thread.Sleep(10000);
}
IL将显示以下外锁代码
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 3
.locals init (
[0] bool flag,
[1] string str,
[2] bool flag2)
L_0000: nop
L_0001: ldc.i4.0
L_0002: stloc.0
L_0003: ldstr "12"
L_0008: dup
L_0009: stloc.1
L_000a: ldloca.s flag
L_000c: call void [mscorlib]System.Threading.Monitor::Enter(object, bool&)
L_0011: nop
L_0012: nop
L_0013: ldstr "outer lock"
L_0018: call void [mscorlib]System.Console::WriteLine(string)
IL代码:
L_0003: ldstr "12"
L_0008: dup
L_0009: stloc.1
L_000a: ldloca.s flag
最终保存" 12"进入当地的变通
"内锁"的IL代码是
.method private hidebysig static void <Main>b__3() cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
.maxstack 2
.locals init (
[0] string str,
[1] bool flag,
[2] string str2,
[3] bool flag2)
L_0000: nop
L_0001: ldstr "1"
L_0006: stloc.0
L_0007: ldc.i4.0
L_0008: stloc.1
L_0009: ldloc.0
L_000a: ldstr "2"
L_000f: call string [mscorlib]System.String::Concat(string, string)
L_0014: dup
L_0015: stloc.2
L_0016: ldloca.s flag
L_0018: call void [mscorlib]System.Threading.Monitor::Enter(object, bool&)
IL代码:
L_0001: ldstr "1"
L_0006: stloc.0
L_0007: ldc.i4.0
L_0008: stloc.1
L_0009: ldloc.0
L_000a: ldstr "2"
L_000f: call string [mscorlib]System.String::Concat(string, string)
商店&#34; 1&#34;在一个局部变量中,并存储&#34; 2&#34;在另一个局部变量中。然后调用String.Concat。
如果您尝试其他代码:(在另一个控制台程序中)
var c = "1" + "2";
var d = c + "2";
Console.WriteLine(string.IsInterned(d));
var e = "12";
Console.WriteLine(string.IsInterned(e));
你会发现第一个字符串.IsInterned(d)什么都不返回,但第二个字符串.IsInterned(e)将打印&#34; 12&#34;在控制台中。
因为c +&#34; 2&#34;在字面上不等于&#34; 1&#34; +&#34; 2&#34;,但&#34; 12&#34;字面上等于&#34; 12&#34;。
这意味着即使是c +&#34; 2&#34;将返回你&#34; 12&#34;,但在内部他们是不同的表达。这意味着你原来的第二个锁定(a +&#34; 2&#34;)&#34;试图锁定不同的表达式,这就是为什么你的第二个代码块会立即执行。