2015-08-26 23 views
4

此代码是否仅锁定在if语句或两行代码上?C#锁定单行(if语句)

lock (LockObject) 
    if (instance == null) 
     instance = Instance(); 
+3

目前它甚至不会编译,因为缺少分号。 – Filburt

+0

或者,您可以使用'懒惰的',它更清楚地显示您的意图,并且它是线程安全的。 –

回答

4

lock锁定整个块。由于它后面没有花括号({}),所以它锁定了一个隐含块 - if语句。在这里,同样的逻辑适用 - 如果条件满足,if执行一个块。由于它后面也没有大括号,所以它隐含有一个包含单个语句的块。换句话说,给定的代码相当于:

lock (LockObject) { 
    if (instance == null) { 
     instance = Instance(); 
    } 
} 
1

它锁定了所有的代码。这里{}if只是略去。

1

if声明包含“then”情况的声明。所以这个锁适用于两条线。

一个简单的经验法则是:如果有{它适用,直到匹配},否则它适用,直到第一个;。这并不包括所有的情况,但肯定是最常见的情况。

0

它锁定了整个声明。考虑下面的例子:

lock (LockObject) 
{ 
    if (instance == null) { 
} 

如果使用括号时仅锁定if条件,那么它会导致编译器的错误,因为它没有被正确布置/匹配。

0

该代码片段锁定了两行代码。

直到if语句执行完成,LockObject才会被释放。这意味着,如果你在第2行条件为真,那么它将会在1号线

希望帮助:)

1

锁定由C#编译器转换为Monitor.EnterMonitor.Exit释放锁之前执行第3。此C#代码

static void Main(string[] args) 
{ 
    lock (LockObject) 
     if (instance == null) 
      instance = Instance(); 
    Console.WriteLine(instance == null); 
} 

,给出以下的IL代码,这清楚地表明,Monitor.Exit(L_0036)instance被分配(L_0026)之后被调用。

两行代码都被锁定。

.method private hidebysig static void Main(string[] args) cil managed 
{ 
    .entrypoint 
    .maxstack 2 
    .locals init (
    [0] bool flag, 
    [1] object obj2, 
    [2] bool flag2) 
    L_0000: nop 
    L_0001: ldc.i4.0 
    L_0002: stloc.0 
    L_0003: ldsfld object TestLock.Program::LockObject 
    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: ldsfld object TestLock.Program::instance 
    L_0017: ldnull 
    L_0018: ceq 
    L_001a: ldc.i4.0 
    L_001b: ceq 
    L_001d: stloc.2 
    L_001e: ldloc.2 
    L_001f: brtrue.s L_002b 
    L_0021: call object TestLock.Program::Instance() 
    L_0026: stsfld object TestLock.Program::instance 
    L_002b: leave.s L_003d 
    L_002d: ldloc.0 
    L_002e: ldc.i4.0 
    L_002f: ceq 
    L_0031: stloc.2 
    L_0032: ldloc.2 
    L_0033: brtrue.s L_003c 
    L_0035: ldloc.1 
    L_0036: call void [mscorlib]System.Threading.Monitor::Exit(object) 
    L_003b: nop 
    L_003c: endfinally 
    L_003d: nop 
    L_003e: ldsfld object TestLock.Program::instance 
    L_0043: ldnull 
    L_0044: ceq 
    L_0046: call void [mscorlib]System.Console::WriteLine(bool) 
    L_004b: nop 
    L_004c: ret 
    .try L_0003 to L_002d finally handler L_002d to L_003d 
} 
2

if声明不能单独执行,它需要块后,为表达true - 案例,因此,作为@Mureinik已经说过,lock锁定整个初始化块。你甚至可以把它写这样的:

lock (LockObject) if (instance == null) instance = Instance(); 

然而,这不建议写你的代码,而在这种情况下,大括号,因为它是非常混乱,难以调试。还要注意的是lock语句是一个语法糖Monitor类的使用,你的代码被编译成这样:

try 
{ 
    Monitor.Enter(LockObject); 
    if (instance == null) 
    { 
     instance = Instance(); 
    } 
} 
finally 
{ 
    Monitor.Exit(LockObject); 
} 

而且我要注意,初始化逻辑你可以使用一个Lazy<T>类,它是线程 - 安全,并没有使用像Monitor那么重的构造,并且可以比你的代码更快地执行。代码将是这样的:

// field in class 
Lazy<Instance> lazyInstance = new Lazy<Instance>(() => Instance()); 

//usage in code 
var instanceValue = lazyInstance.Value;