C#锁单行(if语句)
C# lock single line (if statement)
这段代码是只锁定在 if
语句上,还是锁定在两行代码上?
lock (LockObject)
if (instance == null)
instance = Instance();
它正在锁定所有代码。这里 {
和 }
for if
只是被省略了。
if
语句包含 "then" 案例的语句。所以锁适用于两条线。
一个简单的经验法则是:如果有一个 {
,它将应用到匹配的 }
,否则它应用到第一个 ;
。这不包括 所有 情况,但肯定是最常见的情况。
它正在锁定整个语句。考虑以下示例:
lock (LockObject)
{
if (instance == null) {
}
如果在使用大括号时只锁定if
条件,那么它会导致编译器错误,因为它不是正确的arranged/matched。
lock
锁定整个块。因为它后面没有花括号 ({}
),所以它锁定了一个隐式块 - if
语句。这里,同样的逻辑适用——如果条件满足,if
执行一个块。因为它后面也没有花括号,所以它隐含地有一个包含单个语句的块。换句话说,给定的代码等同于:
lock (LockObject) {
if (instance == null) {
instance = Instance();
}
}
此代码片段锁定了两行代码。
在 if 语句执行完毕之前,LockObject 上的锁不会被释放。这意味着,如果您在第 2 行中的条件为真,那么它将在释放第 1 行中的锁之前执行第 3 行
希望对您有所帮助:)
Lock 由 C# 编译器翻译为 Monitor.Enter
和 Monitor.Exit
。此 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
}
if
语句不能单独执行,对于 true
-表达式的情况,它需要在它之后的块,所以,正如@Mureinik 已经说过的,lock
锁定你的整个初始化块。你甚至可以这样写:
lock (LockObject) if (instance == null) instance = Instance();
但是,在这种情况下不建议编写没有大括号的代码,因为它非常混乱且难以调试。另请注意,lock
语句是 Monitor
class 用法的语法糖,您的代码被编译为:
try
{
Monitor.Enter(LockObject);
if (instance == null)
{
instance = Instance();
}
}
finally
{
Monitor.Exit(LockObject);
}
而且我要注意,对于 初始化逻辑 你可以使用 Lazy<T>
class,它是线程安全的,并且使用不那么重构造为 Monitor
,并且可以比您的代码执行得更快。代码将是这样的:
// field in class
Lazy<Instance> lazyInstance = new Lazy<Instance>(() => Instance());
//usage in code
var instanceValue = lazyInstance.Value;
这段代码是只锁定在 if
语句上,还是锁定在两行代码上?
lock (LockObject)
if (instance == null)
instance = Instance();
它正在锁定所有代码。这里 {
和 }
for if
只是被省略了。
if
语句包含 "then" 案例的语句。所以锁适用于两条线。
一个简单的经验法则是:如果有一个 {
,它将应用到匹配的 }
,否则它应用到第一个 ;
。这不包括 所有 情况,但肯定是最常见的情况。
它正在锁定整个语句。考虑以下示例:
lock (LockObject)
{
if (instance == null) {
}
如果在使用大括号时只锁定if
条件,那么它会导致编译器错误,因为它不是正确的arranged/matched。
lock
锁定整个块。因为它后面没有花括号 ({}
),所以它锁定了一个隐式块 - if
语句。这里,同样的逻辑适用——如果条件满足,if
执行一个块。因为它后面也没有花括号,所以它隐含地有一个包含单个语句的块。换句话说,给定的代码等同于:
lock (LockObject) {
if (instance == null) {
instance = Instance();
}
}
此代码片段锁定了两行代码。
在 if 语句执行完毕之前,LockObject 上的锁不会被释放。这意味着,如果您在第 2 行中的条件为真,那么它将在释放第 1 行中的锁之前执行第 3 行
希望对您有所帮助:)
Lock 由 C# 编译器翻译为 Monitor.Enter
和 Monitor.Exit
。此 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
}
if
语句不能单独执行,对于 true
-表达式的情况,它需要在它之后的块,所以,正如@Mureinik 已经说过的,lock
锁定你的整个初始化块。你甚至可以这样写:
lock (LockObject) if (instance == null) instance = Instance();
但是,在这种情况下不建议编写没有大括号的代码,因为它非常混乱且难以调试。另请注意,lock
语句是 Monitor
class 用法的语法糖,您的代码被编译为:
try
{
Monitor.Enter(LockObject);
if (instance == null)
{
instance = Instance();
}
}
finally
{
Monitor.Exit(LockObject);
}
而且我要注意,对于 初始化逻辑 你可以使用 Lazy<T>
class,它是线程安全的,并且使用不那么重构造为 Monitor
,并且可以比您的代码执行得更快。代码将是这样的:
// field in class
Lazy<Instance> lazyInstance = new Lazy<Instance>(() => Instance());
//usage in code
var instanceValue = lazyInstance.Value;