Home All Groups Group Topic Archive Search About

Monitor.Wait problem

Author
13 Apr 2006 7:25 PM
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

Author
13 Apr 2006 7:32 PM
Jon Skeet [C# MVP]
Liviu Ursu <livi***@gmail.com> wrote:
> 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.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Author
13 Apr 2006 8:50 PM
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 :-)

Show quote
"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MPG.1ea8b7b4a2e0c02498d0b1@msnews.microsoft.com...
> Liviu Ursu <livi***@gmail.com> wrote:
>> 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.
>
> --
> Jon Skeet - <sk***@pobox.com>
> http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
> If replying to the group, please do not mail me too
Author
13 Apr 2006 9:44 PM
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.



Show quote
"Liviu Ursu" <livi***@gmail.com> wrote in message
news:OPnnZvzXGHA.1348@TK2MSFTNGP05.phx.gbl...
> 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 :-)
>
> "Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
> news:MPG.1ea8b7b4a2e0c02498d0b1@msnews.microsoft.com...
>> Liviu Ursu <livi***@gmail.com> wrote:
>>> 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.
>>
>> --
>> Jon Skeet - <sk***@pobox.com>
>> http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
>> If replying to the group, please do not mail me too
>
>
Author
14 Apr 2006 7:24 AM
Jon Skeet [C# MVP]
Liviu Ursu <livi***@gmail.com> wrote:
> 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.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Author
14 Apr 2006 8:42 AM
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 ;-(




Show quote
"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MPG.1ea95e90f6518c4598d0b8@msnews.microsoft.com...
> Liviu Ursu <livi***@gmail.com> wrote:
>> 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.
>
> --
> Jon Skeet - <sk***@pobox.com>
> http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
> If replying to the group, please do not mail me too
Author
14 Apr 2006 9:32 AM
Jon Skeet [C# MVP]
Liviu Uba <u**@totalsoft.ro> wrote:
> 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.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too

AddThis Social Bookmark Button