Does this use of Monitor.Wait/Pulse have a race condition?
- by jw
I have a simple producer/consumer scenario, where there is only ever a single item being produced/consumed. Also, the producer waits for the worker thread to finish before continuing. I realize that kind of obviates the whole point of multithreading, but please just assume it really needs to be this way (:
This code doesn't compile, but I hope you get the idea:
// 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
}
}
Here is the situation that I am not sure about:
Suppose many threads call SetData() with different inputs.
Only one of them will get inside the lock, and the rest will be blocked on Line A.
Suppose the one that got inside the lock sets m_data and makes its way to Line C.
Question: Could the Wait() on Line C allow another thread at Line A to obtain the lock and overwrite m_data before the worker thread even gets to it?
Supposing that doesn't happen, and the worker thread processes the original m_data, and eventually makes its way to Line F, what happens when that Pulse() goes off?
Will only the thread waiting on Line C be able to get the lock? Or will it be competing with all the other threads waiting on Line A as well?
Essentially, I want to know if Pulse()/Wait() communicate with each other specially "under the hood" or if they are on the same level with lock().
The solution to these problems, if they exist, is obvious of course - just surround SetData() with another lock - say, lock(y).
I'm just curious if it's even an issue to begin with.