在 C# 中,如何安全地退出带有 try catch 块的锁?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/639493/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
In C# how can I safely exit a lock with a try catch block inside?
提问by Justin Tanner
Here is an example of an exception happening inside a lock, with a try-catch block.
这是一个在锁内发生异常的示例,带有 try-catch 块。
int zero = 0;
int j = 10;
lock (sharedResource.SyncRoot)
{
try
{
j = j / zero;
}
catch (DivideByZeroException e)
{
// exception caught but lock not released
}
}
How do I safely release this lock in the catch?
我如何安全地释放这个锁?
采纳答案by Mykola Golubyev
Won't it be released automatically?
不会自动释放吗?
From the MSDN lock means
来自MSDN的锁指
System.Threading.Monitor.Enter(x);
try {
...
}
finally {
System.Threading.Monitor.Exit(x);
}
So you don't have to bother.
所以你不必费心。
回答by cgreeno
Wouldnt it just run like so regardless:
不管它是否会像这样运行:
try
{
lock (sharedResource.SyncRoot)
{
int bad = 2 / 0;
}
}
catch (DivideByZeroException e)
{
// exception caught but lock not released
}
finally
{
//release lock
}
回答by Jeff Kotula
The lock will be released when the context of it's block is exited, however that happens. In the code example given above the lock will automatically, safely be released as control exits the final } context.
当它的块的上下文退出时,锁将被释放,但是会发生这种情况。在上面给出的代码示例中,当控制退出最终的 } 上下文时,锁将自动、安全地释放。
回答by Michael
The lock won't be released until you pass out of the scope of the lock(sharedResource.SyncRoot) block. lock (sharedResource.SyncRoot) {}
is basically identical to:
在您超出 lock(sharedResource.SyncRoot) 块的范围之前,不会释放锁。 lock (sharedResource.SyncRoot) {}
基本上等同于:
Monitor.Enter(sharedResource.SyncRoot);
try
{
}
finally
{
Monitor.Exit(sharedResource.SyncRoot);
}
You can either do the Enter/Exit yourself if you want more control, or just rescope the lock to what you want, like:
如果您想要更多控制,您可以自己执行 Enter/Exit,或者只是将锁定范围重新设置为您想要的,例如:
try
{
lock(sharedResource.SyncRoot)
{
int bad = 2 / 0;
}
}
catch (DivideByZeroException e)
{
// Lock released by this point.
}
回答by Grzenio
Your code is perfectly fine. The lock(sth){...}
is translated internally to a try finally
block.
你的代码非常好。在lock(sth){...}
内部转换为try finally
块。
回答by annakata
Proof.
证明。
.method public hidebysig instance void test(int32 i) cil managed
{
// Code size 43 (0x2b)
.maxstack 2
.locals init ([0] int32 bad,
[1] class [mscorlib]System.DivideByZeroException e,
[2] object CS##代码##00)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldfld object WebApplication1.myclass::mutex
IL_0007: dup
IL_0008: stloc.2
IL_0009: call void [mscorlib]System.Threading.Monitor::Enter(object)
IL_000e: nop
.try
{
IL_000f: nop
.try
{
IL_0010: nop
IL_0011: ldc.i4.2
IL_0012: ldarg.1
IL_0013: div
IL_0014: stloc.0
IL_0015: nop
IL_0016: leave.s IL_001d
} // end .try
catch [mscorlib]System.DivideByZeroException
{
IL_0018: stloc.1
IL_0019: nop
IL_001a: nop
IL_001b: leave.s IL_001d
} // end handler
IL_001d: nop
IL_001e: nop
IL_001f: leave.s IL_0029
} // end .try
finally
{
IL_0021: ldloc.2
IL_0022: call void [mscorlib]System.Threading.Monitor::Exit(object)
IL_0027: nop
IL_0028: endfinally
} // end handler
IL_0029: nop
IL_002a: ret
} // end of method myclass::test
回答by Justin Tanner
Jaredpar posted a link in a comment which I think is worth checking out:
Jaredpar 在评论中发布了一个链接,我认为值得一看:
http://blogs.msdn.com/ericlippert/archive/2009/03/06/locks-and-exceptions-do-not-mix.aspx
http://blogs.msdn.com/ericlippert/archive/2009/03/06/locks-and-exceptions-do-not-mix.aspx
In this blog post Eric Lippert comments on the problems related to locking in C#:
在这篇博文中,Eric Lippert 评论了与 C# 中的锁定相关的问题:
The problem here is that if the compiler generates a no-op instruction between the monitor enter and the try-protected region then it is possible for the runtime to throw a thread abort exception after the monitor enter but before the try. In that scenario, the finally never runs so the lock leaks, probably eventually deadlocking the program. It would be nice if this were impossible in unoptimized and optimized builds.
这里的问题是,如果编译器在监视器进入和受保护区域之间生成无操作指令,那么运行时可能会在监视器进入之后但在尝试之前抛出线程中止异常。在这种情况下, finally 永远不会运行,因此锁泄漏,可能最终导致程序死锁。如果这在未优化和优化的构建中是不可能的,那就太好了。