Создание блокирующейся Очереди <T> в.NET?

Загрузка изображения из файла Jar во время выполнения такая же, как загрузка изображения при выполнении из IDE, например, netbeans, разница заключается в том, что при загрузке изображения из JAR-файла путь должен быть правильным и его чувствительный к регистру (очень важно). Это работает для меня

 image1 = new javax.swing.ImageIcon(getClass().getResource("/Pictures/firstgame/habitat1.jpg"));
        img = image1.getImage().getScaledInstance(lblhabitat1.getWidth(), lblhabitat1.getHeight(), Image.SCALE_SMOOTH);
        lblhabitat1.setIcon(new ImageIcon(img));

, если p в «/Pictures/firstgame/habitat1.jpg» в нижнем регистре, он не будет работать. проверки пробелов, случаев и орфографии

161
задан Eric Schoonover 9 February 2009 в 23:05
поделиться

7 ответов

Это выглядит очень небезопасным (очень мало синхронизации); как насчет чего-то как:

class SizeQueue<T>
{
    private readonly Queue<T> queue = new Queue<T>();
    private readonly int maxSize;
    public SizeQueue(int maxSize) { this.maxSize = maxSize; }

    public void Enqueue(T item)
    {
        lock (queue)
        {
            while (queue.Count >= maxSize)
            {
                Monitor.Wait(queue);
            }
            queue.Enqueue(item);
            if (queue.Count == 1)
            {
                // wake up any blocked dequeue
                Monitor.PulseAll(queue);
            }
        }
    }
    public T Dequeue()
    {
        lock (queue)
        {
            while (queue.Count == 0)
            {
                Monitor.Wait(queue);
            }
            T item = queue.Dequeue();
            if (queue.Count == maxSize - 1)
            {
                // wake up any blocked enqueue
                Monitor.PulseAll(queue);
            }
            return item;
        }
    }
}

(редактирование)

В действительности, Вы хотели бы способ закрыть очередь так, чтобы читатели начали выходить чисто - возможно, что-то как флаг bool - если установлено, пустая очередь просто возвращается (вместо того, чтобы блокироваться):

bool closing;
public void Close()
{
    lock(queue)
    {
        closing = true;
        Monitor.PulseAll(queue);
    }
}
public bool TryDequeue(out T value)
{
    lock (queue)
    {
        while (queue.Count == 0)
        {
            if (closing)
            {
                value = default(T);
                return false;
            }
            Monitor.Wait(queue);
        }
        value = queue.Dequeue();
        if (queue.Count == maxSize - 1)
        {
            // wake up any blocked enqueue
            Monitor.PulseAll(queue);
        }
        return true;
    }
}
197
ответ дан Marc Gravell 4 November 2019 в 17:10
поделиться

"Как это может быть улучшено?"

ну, необходимо посмотреть на каждый метод в классе и рассмотреть то, что произошло бы, если бы другой поток одновременно называл тот метод или какой-либо другой метод. Например, Вы вставляете блокировку Удалить метод, но не в Добавить методе. Что происходит, если один поток Добавляет в то же время, что и другой поток Удаляет? Плохие вещи.

Также полагают, что метод может возвратить второй объект, который обеспечивает доступ к внутренним данным первого объекта - например, GetEnumerator. Предположите, что один поток проходит тот перечислитель, другой поток изменяет список одновременно. Не хороший.

А хорошее эмпирическое правило состоит в том, чтобы сделать это более простым разобраться путем сокращения количества методов в классе к абсолютному минимуму.

, В частности, не наследуйте другой контейнерный класс, потому что Вы выставите все методы того класса, позволяющие, чтобы вызывающая сторона повредила внутренние данные, или видеть частично полные изменения в данных (столь же плохо, потому что данные кажутся поврежденными в тот момент). Скройте все подробности и быть абсолютно безжалостными о том, как Вы предоставляете доступ им.

я настоятельно рекомендовал бы, чтобы Вы для использования стандартных решений - получили книгу о поточной обработке или пользовались сторонней библиотекой. Иначе, учитывая то, чего Вы делаете попытку, Вы собираетесь быть отладкой Вашего кода в течение долгого времени.

кроме того, разве это не имело бы большего смысла для, Удаляют для возврата, объект (скажите, тот, который был добавлен сначала, поскольку это - очередь), а не вызывающая сторона, выбирающая определенный объект? И то, когда очередь пуста, возможно, Удалите, должно также заблокироваться.

Обновление: ответ Marc на самом деле реализует все эти предложения!:) Но я оставлю это здесь, поскольку может быть полезно понять, почему его версия является таким улучшением.

14
ответ дан Daniel Earwicker 4 November 2019 в 17:10
поделиться

Ну, Вы могли бы посмотреть System.Threading.Semaphore класс. Кроме этого - нет, необходимо сделать это сами. AFAIK там не является таким встроенным набором.

0
ответ дан Vilx- 4 November 2019 в 17:10
поделиться

Я не полностью исследовал TPL, но у них могло бы быть что-то, что соответствует Вашим потребностям, или по крайней мере, некоторый фураж Отражателя для ловли некоторого вдохновения от.

Hope, которая помогает.

2
ответ дан TheMissingLINQ 4 November 2019 в 17:10
поделиться

Если Вы хотите максимальную пропускную способность, позволяя нескольким читателям читать и только одно устройство записи для записи, BCL имеет что-то названное ReaderWriterLockSlim, который должен помочь сократить код...

-1
ответ дан DavidN 4 November 2019 в 17:10
поделиться

Это то, что я сделал для поточно-безопасной ограниченной блокировки очередь.

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

public class BlockingBuffer<T>
{
    private Object t_lock;
    private Semaphore sema_NotEmpty;
    private Semaphore sema_NotFull;
    private T[] buf;

    private int getFromIndex;
    private int putToIndex;
    private int size;
    private int numItems;

    public BlockingBuffer(int Capacity)
    {
        if (Capacity <= 0)
            throw new ArgumentOutOfRangeException("Capacity must be larger than 0");

        t_lock = new Object();
        buf = new T[Capacity];
        sema_NotEmpty = new Semaphore(0, Capacity);
        sema_NotFull = new Semaphore(Capacity, Capacity);
        getFromIndex = 0;
        putToIndex = 0;
        size = Capacity;
        numItems = 0;
    }

    public void put(T item)
    {
        sema_NotFull.WaitOne();
        lock (t_lock)
        {
            while (numItems == size)
            {
                Monitor.Pulse(t_lock);
                Monitor.Wait(t_lock);
            }

            buf[putToIndex++] = item;

            if (putToIndex == size)
                putToIndex = 0;

            numItems++;

            Monitor.Pulse(t_lock);

        }
        sema_NotEmpty.Release();


    }

    public T take()
    {
        T item;

        sema_NotEmpty.WaitOne();
        lock (t_lock)
        {

            while (numItems == 0)
            {
                Monitor.Pulse(t_lock);
                Monitor.Wait(t_lock);
            }

            item = buf[getFromIndex++];

            if (getFromIndex == size)
                getFromIndex = 0;

            numItems--;

            Monitor.Pulse(t_lock);

        }
        sema_NotFull.Release();

        return item;
    }
}
5
ответ дан 23 November 2019 в 21:26
поделиться

Я только что сделал это с помощью Reactive Extensions и вспомнил этот вопрос:

public class BlockingQueue<T>
{
    private readonly Subject<T> _queue;
    private readonly IEnumerator<T> _enumerator;
    private readonly object _sync = new object();

    public BlockingQueue()
    {
        _queue = new Subject<T>();
        _enumerator = _queue.GetEnumerator();
    }

    public void Enqueue(T item)
    {
        lock (_sync)
        {
            _queue.OnNext(item);
        }
    }

    public T Dequeue()
    {
        _enumerator.MoveNext();
        return _enumerator.Current;
    }
}

Не обязательно полностью безопасно, но очень просто.

6
ответ дан 23 November 2019 в 21:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: