Monitor.Wait problem

L

Liviu Ursu

Hi, I am relatively new to NET Threading and learning from net examples and
books I got a problem that is not mentioned anyware.

Let's say thread1 does following:

Monitor.Enter(o);
try
{
Do X;
Monitor.Wait(o);
Do.Y;
}
finally
{
Monitor.Exit(o);
}

Thread2 does:

Monitor.Enter(o);
try
{
Do A;
Monitor.Pulse(o);
Do.B;
}
finally
{
Monitor.Exit(o);
}

On my dual core processor it happens sometimes that Thread2 ends before
Thread 1 starts, though they are started in order: Thread1, Thread2!!
And there is the problem:

At the moment Thread1 calls Monitor.Wait, thread2 is already finished, so
there is no thread that can call Pulse
So, Thread1 blocks forever.

QUESTION: Why does Monitor.Wait not acquire the lock back if no other
thread holds the lock.
How can I detect this situation and avoid it in an elegant way?

Regards
Liviu
 
J

Jon Skeet [C# MVP]

Liviu Ursu said:
Hi, I am relatively new to NET Threading and learning from net examples and
books I got a problem that is not mentioned anyware.

<snip>

(You should use the lock statement to make things more readable, by the
way.)
On my dual core processor it happens sometimes that Thread2 ends before
Thread 1 starts, though they are started in order: Thread1, Thread2!!
And there is the problem:

At the moment Thread1 calls Monitor.Wait, thread2 is already finished, so
there is no thread that can call Pulse
So, Thread1 blocks forever.

QUESTION: Why does Monitor.Wait not acquire the lock back if no other
thread holds the lock.

Because it waits for the monitor to be pulsed. If another thread is
holding the lock, the thread calling Wait wouldn't be able to hold the
lock at the same time, which means the call to Wait would throw an
exception anyway.
How can I detect this situation and avoid it in an elegant way?

Use a piece of shared data (a boolean, a counter, whatever) to indicate
what's going on. It's hard to give more specifics without knowing what
you're trying to achieve.
 
L

Liviu Ursu

Hi,

Thanx. But exactly that is the problem.
At the time Thread1 calls Monitor.Wait, there is no other thread. It is the
only thread running except the GUI..
I could have left Thread2 away, and say I have just one thread.

Intuitively i don't see any reason Monitor.Wait has to wait if it has
nothing to wait for :)
 
L

Liviu Ursu

Where I see the problem:

No one can know for sure that another Thread will call Pulse after I call
Wait. For simple logic, that maybe the case.
For complex programs....
All examples i saw on the net are just wrong, and they may block forever run
on a multiprocessor machine at least.

I can reproduce on my computer a crazy bug in BackgroundWorker from vsnet
2005, just that the progress method is called in random order 100% 20% 50%,
not in the order actually intended.



Liviu Ursu said:
Hi,

Thanx. But exactly that is the problem.
At the time Thread1 calls Monitor.Wait, there is no other thread. It is
the only thread running except the GUI..
I could have left Thread2 away, and say I have just one thread.

Intuitively i don't see any reason Monitor.Wait has to wait if it has
nothing to wait for :)
 
J

Jon Skeet [C# MVP]

Liviu Ursu said:
Where I see the problem:

No one can know for sure that another Thread will call Pulse after I call
Wait. For simple logic, that maybe the case.
For complex programs....
All examples i saw on the net are just wrong, and they may block forever run
on a multiprocessor machine at least.

They will only block forever if you let them wait when there's nothing
to wait for. In most cases, you would have a "while" loop which would
check whether there's something to wait for before waiting.
I can reproduce on my computer a crazy bug in BackgroundWorker from vsnet
2005, just that the progress method is called in random order 100% 20% 50%,
not in the order actually intended.

That sounds like it's more likely to be a bug in the code *using*
BackgroundWorker than in BackgroundWorker itself.

Could you post a short but complete program which demonstrates the
problem?

See http://www.pobox.com/~skeet/csharp/complete.html for details of
what I mean by that.
 
L

Liviu Uba

Moving to BackGroundWorker :)
The code is the simplest code possible:

for i:= 1 to 100
ProgressChanged(...)

As I told, on my dualcore it is possible that although threads t1 and t2 are
started exactly in this order in code, actually they start in reverse order:
t2, t1

An explanation exists for the behaviour of Bgw, the progresschanged event is
called asynchronously, queued to a ThreadPool thread, so there is really no
guarantee of the order. What is wrong, is that in MSDN there is no comment
on this. Most folks that have a single processor machine never face this
issue until delevering binaries to client's servers ;-(
 
J

Jon Skeet [C# MVP]

Liviu Uba said:
Moving to BackGroundWorker :)
The code is the simplest code possible:

<snip>

That's not a complete program, which is what I requested.
for i:= 1 to 100
ProgressChanged(...)

As I told, on my dualcore it is possible that although threads t1 and t2 are
started exactly in this order in code, actually they start in reverse order:
t2, t1

Yes, but that's a different issue.
An explanation exists for the behaviour of Bgw, the progresschanged event is
called asynchronously, queued to a ThreadPool thread, so there is really no
guarantee of the order. What is wrong, is that in MSDN there is no comment
on this. Most folks that have a single processor machine never face this
issue until delevering binaries to client's servers ;-(

When I've seen a short but complete program which demonstrates the
problem, I'll be able to comment better.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top