2012-12-25 54 views
2

在系統中,我們有通過特定參數鎖定對象的方法。 作爲實現,我們使用LockManager和Enter方法接收鎖的密鑰,檢查鎖對象是否存在於內部字典中,如果不存在,它會創建它並鎖定。.NET多線程:鎖定對象時鎖定了很多時間的日誌

我想要做的是爲特定的鎖定設置「X預期時間」,如果一個對象被鎖定了更多的X時間,我想寫一條消息到我們的日誌。

下面是我的鎖管理器源代碼:

public class MyLockManager<T> 
{ 
    protected Dictionary<T, object> LockDictionary { get; private set; } 

    public MyLockManager() 
    { 
     LockDictionary = new Dictionary<T, object>(); 
    } 

    /// <summary> 
    /// Enters a lock on the key. 
    /// </summary> 
    /// <param name="key">The key to lock.</param> 
    public virtual void Enter(T key) 
    { 
     if (!LockDictionary.ContainsKey(key)) 
     { 
      lock (LockDictionary) 
      { 
       if (!LockDictionary.ContainsKey(key)) 
       { 
        LockDictionary.Add(key, new object()); 
       } 
      } 
     } 

     object lockObj = LockDictionary[key]; 
     Monitor.Enter(lockObj); 
    } 

    /// <summary> 
    /// Releases the lock on the key. 
    /// </summary> 
    /// <param name="key">The key to release.</param> 
    public virtual void Exit(T key) 
    { 
     if (LockDictionary.ContainsKey(key)) 
     { 
      Monitor.Exit(LockDictionary[key]); 
     } 
    } 
} 

現在我想添加一個額外的方法,可以說LockTimoutHandler(T鍵)將被調用,如果特定的鍵對象被鎖定超過X時間。

爲了做到這一點,我想爲「Enter」和「Exit」方法添加一些邏輯。當輸入一個稱爲,東西也會莫名其妙地被註冊運行在X時間LockTimoutHandler,並在「退出」之稱,是東西會以某種未註冊

我的問題是我可以用來代替東西?如何安排方法在X時間內運行,如果之前出現過,則請刪除計劃。它必須非常快速,因爲在我們的情況下,性能非常重要。我知道Timer對象...它可以以延遲的方式執行方法,但它的性能足夠好嗎?我有什麼額外的選擇來實現呢?

注意:只是要清楚,我不是在談論TryEnter。我不想在特定時間內無法鎖定對象的情況下捕捉對象,我想捕獲已鎖定時間過長的對象。

謝謝!

+1

您的輸入法不是線程安全的。你可能會在不同的線程中同時閱讀和寫字典。這可能會導致您的應用程序發生死鎖。 – pstrjds

回答

2

我們也有類似的rquirement,解決這樣說:

  • 鎖定時,設置一個定時器超時傳遞一個狀態對象,包含任何你想要的鑰匙和代表:日誌,力-unlock,......必要的操作爲您的使用情況
  • 當計時器火災,檢查關鍵,如果條目存在電話委託
  • 重要:回收定時器(在線程隊列當量),做不是讓它超出範圍。
  • 當你下一次需要一個計時器時,從循環隊列中取出一個並操作狀態對象 - 只在需要時才創建一個新對象。

這樣可以保持儘可能多的計時器,但不會再發生,只會產生一次分配/取消分配的成本。由於您無法更改計時器的狀態對象,因此您需要更改其內容。

+0

我如何「清除」計時器?我的意思是如果對象快速解鎖,我不想調用該方法。 –

+0

讓計時器開火吧!它會查找字典中的關鍵字,但找不到它,從而什麼都不做。或者,由於您不在鎖字典中存儲任何內容,因此您也可以在其中存儲對定時器的引用,並使用它將其設置爲無窮大。 –

+0

好吧,它看起來像可行的解決方案,但如何計時器性能和線程消費?我們有高負載的應用程序處理不同的請求,恐怕計時器會降低我們的性能太多。 –

1

我認爲你可以做得更簡單。計時器是非常輕的物體,我不會光着身子試圖限制他們的計數。所有的定時器都在線程池的特殊線程中運行,並且非常便宜。

只需創建定時器的字典(如果它會在不同的線程中使用您可能希望將其更改爲ConcurrentDictionary

var timers = new Dictionary<T, Timer>(); 

當添加至您的列表使用此代碼來設置超時:

var timer = new Timer(o => LogMessage("key {0} is being held too long", key)); 
timer.Change(timeout, Timeout.Infinite); 
timers.Add(key, timer); 

注意,定時器將只執行一次 - 後指定的超時 和項目被釋放時,剛剛從字典中刪除定時器:

Timer timer; 
if (timers.TryGetValue(key, out timer)) 
{ 
    timer.Dispose(); 
    timers.Remove(key); 
}