Снятие блокировки при использовании ManualResetEvent - PullRequest
0 голосов
/ 15 апреля 2020

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

Рабочим потокам, для которых выполняются данные, иногда требуется доступ к информации из стороннего компонента. , поэтому они:

  1. Поставить объект запроса в очередь с поддержкой потоков
  2. Вызов WaitOne для ManualResetEvent (для каждого объекта запроса существует один ManualResetEvent)

A * oop, работающий в главном потоке:

  1. Извлекает новые объекты запроса по очереди из очереди
  2. Извлекает запрошенные данные (и оставляет это где-то рабочий может получить)
  3. Вызывает Set на ManualResetEvent, чтобы разбудить рабочий поток, который может извлечь данные и продолжить обработку.

Я, к сожалению, в состоянии гонки, где, как я подозреваю, происходит следующее:

  1. Рабочий помещает объект запроса в очередь
  2. Переключение контекста в основной поток
  3. Main нить l oop тянет в очередь объект equest, извлекает данные и сохраняет результат (как и ожидалось)
  4. Основной поток вызывает Set на ManualResetEvent ( НО НИКТО НЕ ЖДЕТ ЭТОГО! )
  5. Переключение контекста обратно на рабочий поток
  6. Рабочий поток вызывает WaitOne на ManualResetEvent
  7. Тупик - рабочий никогда не просыпается

I пытался использовать оператор lock для переноса критической секции следующим образом:

ManualResetEvent myEvent = new ManualResetEvent(false);

void enqueue()
{
     InfoRequest ir = new InfoRequest(...);

     lock(blockingCollection)
     {
         blockingCollection.Add(ir);
         myEvent.WaitOne();
     }

     // Continue execution
}

void mainThread()
{
    while(true)
    {
         var ir = blockingCollection.Take();
         // Do 3rd-party component stuff with ir
         // and save result

         lock(blockingCollection)
         {
             myEvent.Set();
         }
    }
}

Однако, к сожалению, рабочий поток не снимает блокировку при вызове WaitOne, что, очевидно, приводит к тупиковой ситуации, как только WaitOne называется.

Как правильно справиться с этой ситуацией в C#?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...