在C#中,如何使用try catch块安全地退出锁?

时间:2009-03-12 16:47:08

标签: c#

以下是使用try-catch块在锁内发生异常的示例。

int zero = 0;
int j = 10;

lock (sharedResource.SyncRoot)
{
    try
    {
        j = j / zero;
    }
    catch (DivideByZeroException e)
    {
        // exception caught but lock not released
    }
}

如何在捕获中安全释放此锁?

7 个答案:

答案 0 :(得分:36)

不会自动发布吗?

来自MSDN锁定手段

System.Threading.Monitor.Enter(x);
try {
   ...
}
finally {
   System.Threading.Monitor.Exit(x);
}

所以你不必费心。

答案 1 :(得分:13)

在您超出锁定(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.
}

答案 2 :(得分:6)

证明。

.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

答案 3 :(得分:5)

Jaredpar在评论中发布了一个链接,我认为值得一试:

http://blogs.msdn.com/ericlippert/archive/2009/03/06/locks-and-exceptions-do-not-mix.aspx

在这篇博文中,Eric Lippert评论了与锁定C#相关的问题:

  

这里的问题是,如果   编译器生成无操作指令   显示器之间进入和   尝试保护区域然后它   运行时可以抛出一个   线程中止后的异常   监视器输入但在尝试之前。在   那个场景,终于永远不会运行   所以锁可能最终泄漏   使该计划陷入僵局。这将是   很好,如果这是不可能的   未经优化和优化的构建。

答案 4 :(得分:3)

你的代码非常好。 lock(sth){...}内部翻译为try finally块。

答案 5 :(得分:1)

无论如何都不会这样运行:

try
{
  lock (sharedResource.SyncRoot)
  {
      int bad = 2 / 0;
  }
}
catch (DivideByZeroException e)
{
    // exception caught but lock not released
}
finally
{
      //release lock
}

答案 6 :(得分:1)

当退出锁定的上下文时,锁定将被释放,但是会发生这种情况。在上面给出的代码示例中,当控件退出最终的上下文时,锁将自动安全地释放。