2011-02-03 56 views
3

我有一個由兩個函數調用分隔的代碼中的關鍵部分,如Start()End()。他們在執行期間使用Monitor來阻止其他線程。現在我的問題是,如果某個線程無論出於何種原因都不會撥打End(),我的整個過程都會遇到麻煩,因爲每個線程都在等待這個Monitor的發佈。從監視器的所有者的另一個線程釋放鎖

當然我可以使用TryEnter超時,這樣我就不會永久等待,但是這不會釋放被阻止的Monitor,所以我的程序每次都會從這個時間開始進入這個超時。

如果給定的超時結束,是否有辦法從另一個線程釋放阻塞Monitor

void Start(){ Monitor.Enter(obj); } 

void End(){ Monitor.Exit(obj); } 

編輯: 我們通過COM調用Excel互操作,我們不能確保預期Excel進程將一直工作。請注意,這是一個Web應用程序,因此未能處理這種情況是致命的。 Start()稱爲第一次,請求調用excel函數,End()在請求結束時調用。 excel過程總是有可能開始掛起。

EDIT2: 我現在HDA的想法耳鼻喉科鎖的所有者存儲在變量和僵局,我可以殺了這個線程。這不會釋放鎖嗎?

     if (Monitor.TryEnter(excelLocker, 10000) == false) 
         { 
          excelOwner.Abort(); 
          excelOwner = null; 
         } 
         else 
         { 
          excelOwner = Thread.CurrentThread; 
         } 
+0

爲什麼不在你的方法中設置一些簡單的(...),直到達到某個閾值,然後在那一刻爆發? – 2011-02-03 17:17:32

+2

不要試圖修補代碼中的錯誤。修復錯誤。 – 2011-02-03 17:24:53

+0

@Hans Passant:這不是爲了解決*我們的錯誤。我們通過com interop調用Excel,但我們無法確定Excel過程將始終按預期工作。請注意,這是一個Web應用程序,因此未能處理這種情況是致命的。 – codymanix 2011-02-03 17:35:26

回答

0

也許,但你只是隱藏了真正的問題。

你真正需要弄清楚的是爲什麼你的鎖沒有被釋放。如果這是C++,你應該使用一個警衛(這樣即使發生某些事情也會釋放鎖)。

2

唯一可以釋放鎖的線程是擁有該鎖的線程。所以不,你不能直接從另一個線程「解鎖」顯示器 - 這是不可能的設計。如果你能夠做到這一點,其他線程就可以通過釋放它來覆蓋鎖的語義,因爲它們實際上並不擁有它。

我很想知道爲什麼你不使用lock塊,以便保證EnterExit,而不是直接使用Monitor

更新

閱讀您的評論我會強烈建議組織代碼,這樣就可以定位你的鎖,而不是要求起動,並要求結束之後。如果您使用lock,則仍然可以序列化對Excel的訪問,但可以保證調用EnterExit

FYI a lock是一個Monitor在引擎蓋下。

lock(_syncObj) 
    { 
     //Do stuff 
    } 

    //Is equivalent to 

    Monitor.Enter(_syncObj); 
    try 
    { 
     //Do stuff 
    } 
    finally 
    { 
     Monitor.Exit(_syncObj); 
    } 

使用lock可以按如下方式定位您的Excel鎖定:

//Client code 
    ExcelUtil.DoStuff("bling") 

    //... 

    //Util class manages call to Excel and locking. 
    public static class ExcelUtil 
    { 
     private static readonly object SyncObj = new object(); 

     public static void DoStuff(string someParam) 
     { 
      //Guaranteed locking and unlocking even if an exception occurs 
      lock (SyncObj) 
      { 
       DoSomeStuffWithExcelFuncA(); 
       DoSomeStuffWithExcelFuncB(); 
      } 
     } 

     private static void DoSomeStuffWithExcelFuncA() 
     { 
      //... 
     } 

     private static void DoSomeStuffWithExcelFuncB() 
     { 
      //... 
     } 
    } 

順便說一句,你爲什麼鎖定訪問到Excel?我猜你正在爲你的ASP.Net應用程序使用Excel自動化服務器端。除非事態明顯發展,否則這至少在幾年之後總是非常麻煩。如果你拿出一個鎖並且Excel掛起,你就塞滿了。可以使用第三方解決方案來代替Excel自動化。也許更新版本的Excel就像這樣被使用?

你的模式出現,以連載的所有請求,以便只有一個單一的(基於Excel)的請求可以在任一週時間被執行 - 這似乎並不很理想。

0

>>如果某個線程簡化版,調用完()不管是什麼原因,我的整個過程是麻煩,因爲每個線程正在等待得到釋放這個監視器。

讓準確地說,我看到2個原因,一些線程不通話結束():

  • 此線程仍在執行,它是OK的情況,除非你試圖使用資源這不可用此刻並繼續嘗試。因此,如果你嘗試手動停止這個線程(從另一個線程就像你說的),那麼你有危險,你的數據將處於不一致的狀態 - 就像調用Thread.Abort()一樣。

  • 正常的執行流程被異常打破。因此,您需要清理資源並在簡單的try/finally塊中釋放此監視器。

更新

如果是Excel是它往往會拋出異常,通知它在高負載下不可用。最近在Code Review. StackExchange討論了這個話題,以及如何處理這種情況。

另一種策略來應對情況下,當你不確定你會等待多久上的鎖是使用Monitor.TryEnter(object, ref bool)。它是專門設計用於您不想在顯示器上等待一段時間但採取其他一些操作的情況 - 因此您根本不會阻止。

相關問題