Блокировка реализации ObjectPool - PullRequest
3 голосов
/ 23 февраля 2011

Я реализовал универсальный класс 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 ]

3 голосов
/ 23 февраля 2011

Возможно, тупик возникает с stack.Count > 0.Это означает, что у вас есть проблема Ожидание / Пульс.Неплохая идея всегда вызывать Pulse после Push ().Или, по крайней мере, когда граф <5 или около того.Помните, что механизм Wait / Pulse не имеет памяти.</p>

Сценарий:

Поток A пытается получить из пустого пула и выполняет Wait ()
Поток B пытается получить из пустого пула и выполняетWait ()

нить C вставляет в пул, делает импульс ()
нить D возвращает в пул и не дает импульса (счет == 2)

нить A являетсяактивируется и получает свой предмет.
Тема B оставлена ​​в ожидании.С небольшой надеждой на выздоровление.

0 голосов
/ 24 февраля 2011

Хенк ответил на ваш вопрос. Следующее условие не является правильным:

if (stack.Count == 1)
0 голосов
/ 23 февраля 2011

Просто предположение, но как насчет удаления условия «stack.Count == 1» и всегда выдачи импульса внутри функции Put?Возможно, два Puts вызываются быстро по очереди, и пробуждается только один ожидающий поток ..

0 голосов
/ 23 февраля 2011

Теперь я вижу это немного яснее. Я должен иметь блокировку считывателя, верно?

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