簡體   English   中英

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

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

以下是使用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#相關的問題:

這里的問題是,如果編譯器在監視器輸入和嘗試保護區域之間生成無操作指令,則運行時可能會在監視器進入之后但在嘗試之前拋出線程中止異常。 在那種情況下,最終永遠不會運行,因此鎖泄漏,可能最終導致程序死鎖。 如果在未優化和優化的構建中這是不可能的,那將是很好的。

你的代碼非常好。 lock(sth){...}在內部轉換為try finally塊。

無論如何都不會這樣運行:

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

鎖定將在其塊的上下文退出時釋放,但是會發生這種情況。 在上面給出的代碼示例中,當控件退出最終的上下文時,鎖將自動安全地釋放。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM