2011-02-23 78 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)