2013-05-11 20 views
5

我有一個c#程序作爲客戶端和許多客戶端程序,這又是一個c#windows應用程序連接到這個c#服務器程序從sqlite數據庫讀取數據。爲了避免鎖定問題,連接多個客戶端時,我用下面的代碼,return finally before finally

System.Threading.Monitor.Enter(Lock); 

try      
{      
    filter.Execute();//get data from database 
    Request.Clear(); 
    return filter.XML;//create xml and return to client 
} 
finally 
{ 
    System.Threading.Monitor.Exit(Lock); 
} 

服務器獲取掛起一些時間,需要重新啓動服務器程序。 終於做出返回聲明是一個好習慣嗎?

問候 桑傑塔

+1

這只是編寫** lock **語句的難題。否則確保只有一個進程可以使用SqlLite,您將需要使用命名的Mutex。 – 2013-05-11 11:07:15

回答

4

MSDN

通過使用finally塊,可以清理在try塊中分配的任何資源,即使try塊中發生異常,也可以運行代碼。通常,控制離開try語句時finally語句運行。正常執行,中斷執行,continue,goto或return語句或者try語句外的異常傳播可能導致控制權轉移。

在處理的異常中,保證關聯的finally塊被運行。但是,如果異常未處理,finally塊的執行取決於如何觸發異常展開操作。這反過來又取決於你的電腦設置方式。有關更多信息,請參閱CLR中的未處理的異常處理。

2

是的,這就是finally語句是。它將在return後執行,即使發生異常

編輯: 這個簡單的代碼會告訴你,是不是需要一個catch塊的finally塊來執行

public Form1() 
{ 
    InitializeComponent(); 
    check(); 
} 

private string check() 
{ 
    try 
    { 
     return String.Empty; 
    } 
    finally 
    { 
     MessageBox.Show("finally"); 
    } 
} 
+1

什麼?那個怎麼樣???你有什麼材料? – 2013-05-11 10:29:00

+0

@ bash.d在調試器中運行OP的代碼,您將看到:) – VladL 2013-05-11 10:37:06

+0

@ bash.d它是定義的行爲。你有沒有讀過你發佈的內容? :D「通常情況下,當控制器離開try語句時finally語句運行時,控制權的轉移可能是正常執行的結果......或者返回語句」 – VladL 2013-05-11 10:51:32

1

由於您沒有catch塊,因此不能保證最終會被執行。從MSDN - try-finally (C# Reference)"Locks and exceptions do not mix" (Eric Lippert)

在一個處理的異常,與之關聯的finally塊保證 中運行。但是,如果異常未處理,則,finally塊的執行取決於異常展開操作如何觸發 觸發。這反過來又取決於你的電腦設置方式。

然後從提到的鏈接(Unhandled Exception Processing In The CLR)那裏有各種各樣的考慮可能意味着你最終以一個終止的線程。我不老實地知道這是否會讓你鎖定鎖對象。

如果你想確保:

  • 您解除鎖定;但
  • 你不想在這個級別來處理異常,而不是你希望由更高級別的異常處理程序處理

然後做:

TheXmlType xml = null; 
Monitor.Enter(Lock); 
bool inLock = true; 
try { 
    ... 
    xml = filter.Xml; // put this here in case it throws an exception 
    inLock = false; // set this here in case monitor.exit is to 
    // throw an exception so we don't do the same all over again in the catch block 
    Monitor.Exit(Lock); 
    return xml; // this is fine here, but i would normally put it outside my try 
} 
catch (Exception) { 
    if (inLock) Monitor.Exit(Lock); 
    throw; 
} 

但是,請注意:不要不會使用catch (Exception)來隱藏異常,只有當您重新拋出異常時纔可以。人們還建議你有一個return聲明,通常這將在你的try塊之外。

編輯:

與測試程序確認,並從MSDN - Exceptions in Managed Threads

與.NET Framework 2.0版,公共語言運行庫 允許線程最未處理的異常進行 啓動自然。在大多數情況下,這意味着未處理的異常 會導致應用程序終止。

所以,如果你不處理你的異常,你的應用程序將崩潰(你不必擔心鎖定)。如果你確實處理了它,那麼你的原始代碼將會執行它,最終會被阻止,並且你沒事。

編輯2:測試代碼更新,因爲它沒有正確地說明了非火終於:

class Program 
{ 
    static void Main(string[] args) { 
     Program p =new Program(); 
     p.Start(); 
     Console.WriteLine("done, press enter to finish"); 
     Console.ReadLine(); 
    } 

    private readonly object SyncRoot = new object(); 
    ManualResetEvent mre = new ManualResetEvent(false); 

    private void Start() { 
     /* 
     * The application will run the thread, which throws an exception 
     * While Windows kicks in to deal with it and terminate the app, we still get 
     * a couple of "Failed to lock" messages 
     * */ 

     Thread t1 = new Thread(SetLockAndTerminate); 
     t1.Start(); 
     mre.WaitOne(); 
     for (int i = 0; i < 10; i++) { 
      if (!Monitor.TryEnter(this.SyncRoot, 1000)) { 
       Console.WriteLine("Failed to lock"); 
      } 
      else { 
       Console.WriteLine("lock succeeded"); 
       return; 
      } 
     } 
     Console.WriteLine("FINALLY NOT CALLED"); 
    } 
    public int CauseAnOverflow(int i) 
    { 
     return CauseAnOverflow(i + 1); 
    } 
    public void SetLockAndTerminate() { 
     Monitor.Enter(this.SyncRoot); 
     Console.WriteLine("Entered"); 
     try { 
      mre.Set(); 
      CauseAnOverflow(1); // Cause a stack overflow, prevents finally firing 
     } 
     finally { 
      Console.WriteLine("Exiting"); 
      Monitor.Exit(this.SyncRoot); 
     } 
    } 
} 
0

Is it bad practice to return from within a try catch finally block?
它是用C#編寫異常處理的正確方法,並始終finally塊將被執行它並不取決於返回的地點。 我不知道你的代碼,但你應該在其他地方找到你的問題(例如,如果你的代碼是在IIS中託管的,我會懷疑Lock對象在不同的​​加載域中的狀態,或者鎖只是針對一個來電,發生在數據庫或什麼是Request.Clear()你沒有鎖塊嗎?)。您可以輕鬆記錄來電狀態並查找問題。