У меня есть простой сценарий производителя / потребителя, где когда-либо производится или потребляется только один предмет. Кроме того, производитель ожидает завершения рабочего потока, прежде чем продолжить. Я понимаю, что это устраняет весь смысл многопоточности, но, пожалуйста, просто предположите, что это действительно так ((
)
Этот код не компилируется, но я надеюсь, что вы поняли:
// m_data is initially null
// This could be called by any number of producer threads simultaneously
void SetData(object foo)
{
lock(x) // Line A
{
assert(m_data == null);
m_data = foo;
Monitor.Pulse(x) // Line B
while(m_data != null)
Monitor.Wait(x) // Line C
}
}
// This is only ever called by a single worker thread
void UseData()
{
lock(x) // Line D
{
while(m_data == null)
Monitor.Wait(x) // Line E
// here, do something with m_data
m_data = null;
Monitor.Pulse(x) // Line F
}
}
Вот ситуация, в которой я не уверен:
Предположим, что многие потоки вызывают SetData () с разными входами.
Только один из них попадет внутрь замка, а остальные будут заблокированы на линии А.
Предположим, что тот, кто попал внутрь замка, устанавливает m_data и пробивается к линии C.
Вопрос: Может ли Wait () в строке C разрешить другому потоку в строке A получить блокировку и перезаписать m_data до того, как рабочий поток даже доберется до него?
Предположим, что этого не происходит, и рабочий поток обрабатывает исходные m_data и, в конце концов, попадает в Строку F, что произойдет, когда этот Pulse () отключится?
Сможет ли блокировка получить только поток, ожидающий на линии C? Или он будет конкурировать со всеми остальными потоками, ожидающими и в строке A?
По сути, я хочу знать, взаимодействуют ли Pulse () / Wait () друг с другом специально «под колпаком» или находятся ли они на одном уровне с lock ().
Решение этих проблем, если они существуют, конечно, очевидно - просто окружите SetData () другой блокировкой - скажем, lock (y).
Мне просто любопытно, если это вообще проблема для начала.