ObjectPool实现死锁

时间:2011-02-23 15:52:53

标签: c# multithreading monitor

我已经实现了一个通用的ObjectPool类,但是经历过它有时死锁(发生在Monitor.Wait(poolLock))

有人能发现错误吗?

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);
        }

4 个答案:

答案 0 :(得分:3)

死锁可能发生在stack.Count > 0。这意味着您有等待/脉冲问题。在Push()之后总是调用Pulse并不是一个坏主意。或者至少当Count&lt; 5左右。请记住,Wait / Pulse机制没有内存。

场景:

  

线程A尝试从空中获取   池,并做一个Wait()
  线程B尝试   从一个空池中获取,然后做一个   等待()

     

线程C进入池中,是否有脉冲()   线程D放回池中而不是Pulse(Count == 2)

     

线程A被激活并获取其项目   线程B保持等待。对复苏没什么希望。

答案 1 :(得分: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();
        }
    }
}

答案 2 :(得分:0)

只是一个猜测,但是如何删除“stack.Count == 1”条件并始终在Put函数内部发出一个Pulse?也许两个Puts按顺序快速调用,只有一个等待线程被唤醒..

答案 3 :(得分:0)

Henk回答了你的问题。以下条件不正确:

if (stack.Count == 1)