以下是使用try-catch块在锁内发生异常的示例.
int zero = 0; int j = 10; lock (sharedResource.SyncRoot) { try { j = j / zero; } catch (DivideByZeroException e) { // exception caught but lock not released } }
如何在捕获中安全地释放此锁定?
它不会自动发布吗?
从MSDN锁定手段
System.Threading.Monitor.Enter(x); try { ... } finally { System.Threading.Monitor.Exit(x); }
所以你不必费心.
在您超出锁定(sharedResource.SyncRoot)块的范围之前,不会释放锁定. lock (sharedResource.SyncRoot) {}
基本上与:
Monitor.Enter(sharedResource.SyncRoot); try { } finally { Monitor.Exit(sharedResource.SyncRoot); }
如果您想要更多控制,您可以自己进入/退出,或者只是将锁定重新锁定到您想要的位置,例如:
try { lock(sharedResource.SyncRoot) { int bad = 2 / 0; } } catch (DivideByZeroException e) { // Lock released by this point. }
证明.
.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$2$0000) 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
Jaredpar在评论中发布了一个链接,我认为值得一试:
http://blogs.msdn.com/ericlippert/archive/2009/03/06/locks-and-exceptions-do-not-mix.aspx
在这篇博文中,Eric Lippert评论了与锁定C#相关的问题:
这里的问题是,如果编译器在监视器输入和尝试保护区域之间生成无操作指令,则运行时可能会在监视器进入之后但在尝试之前抛出线程中止异常.在那种情况下,最终永远不会运行,因此锁泄漏,可能最终导致程序死锁.如果在未优化和优化的构建中这是不可能的,那将是很好的.