Достаточно ли проверки размера ManualResetEvent для ожидания нескольких потоков? - PullRequest
0 голосов
/ 28 февраля 2012

В настоящее время я использую ManualResetEvent для одного потока, чтобы дождаться, пока несколько потоков добавят что-либо в очередь диспетчера потоков.Если диспетчер потоков получает сигнал с использованием события ручного сброса, он удаляет добавленный элемент и выполняет дальнейшую обработку.Моя единственная проблема заключается в том, что если сработало несколько наборов, то другой элемент очереди не будет обработан.(см. точка B )

while (IsThreadRunning)
{
    // A: My workaround is to check if queue has item, if not then wait for other thread to set the event
    if (DataQueue.Count <= 0)
    {
        ResetEvent.WaitOne();
    }

    // B: At this point two thread added item to the queue and did ResetEvent.Set() twice.
    if (DataQueue.Count > 0)
    {
        DataQueue.Dequeue();
    }

    // Reset the event to avoid processor hog
    ResetEvent.Reset();
}

Мой обходной путь здесь заключается в добавлении условия размера очереди в точку A .Есть ли другой способ сделать это, чтобы избежать взаимоблокировки?

Примечание. Обычный сценарий, приведенный в примере использования ManualResetEvent, состоит в том, что существует несколько потоков, ожидающих (ManualResetEvent.Wait) для события в одном потоке, ноздесь несколько потоков запускает (ManualResetEvent.Set) событие.Есть ли другой класс, который используется для этого сценария?

Ответы [ 2 ]

1 голос
/ 28 февраля 2012

Теперь сбросить событие ручного сброса. Не используйте какие-либо события для этого. Используйте семафор и замок. В методе push заблокируйте очередь, поместите объект в очередь, выйдите из блока оператора блокировки и затем подайте сигнал семафору. В методе pop дождитесь семафора, затем заблокируйте очередь, вытолкните объект и выйдите из блока оператора блокировки.

Это если вы действительно хотите доморощить очереди производителей и потребителей. Если вы хотите, чтобы очередь уже работала, посмотрите на классы BlockingCollection.

1 голос
/ 28 февраля 2012

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

Когда событие сигнализируется, немедленно сбросить его.

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

while (IsThreadRunning)
{
  while ( DataQueue.Count > 0 )
  {
    DataQueue.Dequeue();
  }
  ResetEvent.WaitOne();
  ResetEvent.Reset();
}
...