简体   繁体   English

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

[英]In C# how can I safely exit a lock with a try catch block inside?

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? 如何在捕获中安全地释放此锁定?

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. 所以你不必费心。

The lock won't be released until you pass out of the scope of the lock(sharedResource.SyncRoot) block. 在您超出锁定(sharedResource.SyncRoot)块的范围之前,不会释放锁定。 lock (sharedResource.SyncRoot) {} is basically identical to: 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: 如果您想要更多控制,您可以自己进入/退出,或者只是将锁定重新锁定到您想要的位置,例如:

try
{
    lock(sharedResource.SyncRoot)
    {
        int bad = 2 / 0;
    }
}
catch (DivideByZeroException e)
{
   // Lock released by this point.
}

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$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 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. 如果在未优化和优化的构建中这是不可能的,那将是很好的。

Your code is perfectly fine. 你的代码非常好。 The lock(sth){...} is translated internally to a try finally block. lock(sth){...}在内部转换为try finally块。

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
}

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. 在上面给出的代码示例中,当控件退出最终的上下文时,锁将自动安全地释放。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM