2011-02-23 76 views
3

我實現了一個通用的ObjectPool的類,但經歷過這一段死鎖(發生在Monitor.Wait(poolLock))ObjectPool的實現死鎖

任何人都可以發現這個錯誤嗎?

public class ObjectPool<T> where T : new() 
{ 
    private readonly object poolLock = new object(); 
    Stack<T> stack = null; 

    public ObjectPool(int count) 
    { 
     stack = new Stack<T>(count); 
     for (int i=0; i<count; i++) 
      stack.Push(new T()); 
    } 

    public T Get() 
    { 
     lock (poolLock) 
     { 
      //if no more left wait for one to get Pushed 
      while (stack.Count < 1) 
       Monitor.Wait(poolLock); 
      return stack.Pop(); 
     } 
    } 

    public void Put(T item) 
    { 
     lock (poolLock) 
     { 
      stack.Push(item); 
      //If adding first send signal 
      if (stack.Count == 1) 
       Monitor.Pulse(poolLock); 
     } 
    } 

使用

 try 
     { 
      service = myPool.Get(); 
     } 
     finally 
     { 
      if (service != null) 
       myPool.Put(service); 
     } 
+0

好的拼圖。當它死鎖時,是否與stack.Count == 0? – 2011-02-23 16:05:08

+0

它是Monitor.Wait(poolLock)阻止。 – Stig 2011-02-23 17:06:32

回答

3

死鎖可能發生在stack.Count > 0。這意味着你有一個等待/脈衝問題。在Push()後總是調用Pulse並不是一個壞主意。或至少當計數< 5左右。請記住,等待/脈衝機制沒有內存。

一個場景:

線程A試圖從空 池來獲取,並執行()
線程B試圖 從空池獲取一個等待,並做了 等待()

線程C-放入池,一個是否脈衝()
螺紋d放回到池和不脈衝(計數== 2)

線程A被激活並獲取其項目。
線程B正在等待。幾乎沒有希望恢復。

0

我看到了一個更加清楚一點了。我必須有讀卡器鎖,對吧?

public T Get() 
{ 
    lock (readerLock) 
    { 
     lock (poolLock) 
     { 
      //if no more left wait for one to get Pushed 
      while (stack.Count < 1) 
       Monitor.Wait(poolLock); 
      return stack.Pop(); 
     } 
    } 
} 
+1

不,這沒什麼幫助。 – 2011-02-23 16:09:49

+0

它有助於我的整合測試。此外,我想我總是可以Monitor.Pulse,而不是隻有當計數爲1. – Stig 2011-02-23 17:09:21

+0

併發性的問題是,它是如此非常難以測試。 – 2011-02-23 17:13:08

0

只是一個猜測,但如何去除「stack.Count == 1」條件並始終在Put函數內發出一個Pulse?也許兩個被按順序快速調用,只有一個等待線程被喚醒..

0

Henk回答了你的問題。以下情況不正確:

if (stack.Count == 1)