Вопрос

Мне нужно реализовать допущенную очередью производителя / потребителя, несколько потребителей против одного производителя.

У меня есть функция push, которая добавляет элемент в очередь, а затем проверяет maxsize. Если мы достигли его, верните FALSE, в любом другом случае вернитесь.

В следующем коде _Vector - это списокu003CT> OnSignal в основном потребляет предмет в асинхронном пути.

Вы видите проблемы с этим кодом?

public bool Push(T message)
{
    bool canEnqueue = true;

    lock (_vector)
    {
        _vector.Add(message);
        if (_vector.Count >= _maxSize)
        {
            canEnqueue = false;
        }
    }

    var onSignal = SignalEvent;
    if (onSignal != null)
    {
        onSignal();
    }

    return canEnqueue;
}
Это было полезно?

Решение

Я знаю, что вы сказали, что однопроизводитель, многократный потребитель, но все равно стоит упомянуть: если ваша очередь почти полна (скажем, 24 из 25 слотов), то если два потока Push В то же время вы в конечном итоге превышаете предел. Если есть даже шанс, у вас может быть несколько производителей в какой-то момент в будущем, вы должны рассмотреть Push Блокирующий вызов, и у него дождаться «доступное» AutoResetEvent который сигнализируется после удаления элемента, либо после того, как элемент трансформируется, когда доступны еще слоты.

Единственная другая потенциальная проблема, которую я вижу, это SignalEvent. Отказ Вы не показываете нам реализацию этого. Если он объявлен как public event SignalEventDelegate SignalEvent, тогда вы будете в порядке, потому что компилятор автоматически добавляет SynchronizedAttribute. Отказ Однако, если SignalEvent использует делегат поддержки с add/remove Синтаксис, то вам нужно будет предоставить свою собственную блокировку для самого мероприятия, в противном случае будет возможно для потребителя от события чуть немного поздно и по-прежнему получить пару сигналов позже.

Редактировать: на самом деле, это возможно независимо; Что еще более важно, если вы использовали делегат «Добавить / удалить стиль свойств без соответствующего блокировки», на самом деле возможно для делегата в неверном состоянии, когда вы пытаетесь выполнить его. Даже с синхронизированным событием потребителей должны быть готовы получать (и отбросить) уведомления после того, как они отказываются отписались.

Кроме того, я не вижу проблем - хотя это не значит, что нет, это просто означает, что я не заметил никого.

Другие советы

Самая большая проблема, которую я вижу, есть использование List<T> реализовать очередь; Существуют проблемы с производительностью, поскольку удаление первого элемента включает копирование всех данных.

Дополнительные мысли; Вы поднимаете сигнал, даже если вы не Добавить данные и использование событий сам может иметь проблему с резьбой (есть несколько краевых чехлов, даже если вы зарабатываете значение до null Тест - плюс это возможно больше накладных расходов, чем использование Monitor сделать сигнализацию).

Я бы перешел на Queue<T> что не будет иметь эту проблему - или лучше использовать предварительно прокатный пример; Например Создание блокирующей очереди в .NET?, который имеет именно то, что вы обсуждаете, и поддерживает любое количество как производителей, так и потребителей. Он использует блокирующий подход, но «попробуйте» подход будет:

public bool TryEnqueue(T item)
{
    lock (queue)
    {
        if (queue.Count >= maxSize) { return false; }
        queue.Enqueue(item);
        if (queue.Count == 1)
        {
            // wake up any blocked dequeue
            Monitor.PulseAll(queue);
        }
        return true;
    }
}

Наконец - не «нажимаешь» на куча, не очередь?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top