Я создаю приложение с основным потоком и рабочим пулом потоков. В главном потоке есть экземпляр стороннего незащищенного компонента (доступ к которому возможен только в главном потоке).
Рабочим потокам, для которых выполняются данные, иногда требуется доступ к информации из стороннего компонента. , поэтому они:
- Поставить объект запроса в очередь с поддержкой потоков
- Вызов
WaitOne
для ManualResetEvent
(для каждого объекта запроса существует один ManualResetEvent
)
A * oop, работающий в главном потоке:
- Извлекает новые объекты запроса по очереди из очереди
- Извлекает запрошенные данные (и оставляет это где-то рабочий может получить)
- Вызывает
Set
на ManualResetEvent
, чтобы разбудить рабочий поток, который может извлечь данные и продолжить обработку.
Я, к сожалению, в состоянии гонки, где, как я подозреваю, происходит следующее:
- Рабочий помещает объект запроса в очередь
- Переключение контекста в основной поток
- Main нить l oop тянет в очередь объект equest, извлекает данные и сохраняет результат (как и ожидалось)
- Основной поток вызывает
Set
на ManualResetEvent
( НО НИКТО НЕ ЖДЕТ ЭТОГО! ) - Переключение контекста обратно на рабочий поток
- Рабочий поток вызывает
WaitOne
на ManualResetEvent
- Тупик - рабочий никогда не просыпается
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#?