PC Review


Reply
Thread Tools Rate Thread

Conceptual Problem with Monitor.Enter and Monitor.Exit

 
 
AliRezaGoogle
Guest
Posts: n/a
 
      16th Jun 2008
Dear Members,
I have a problem in the concepts of Monit.Enter and Monitor.Exit
(Before everything I should say that I know how to solve this problem
by

using Monitor.Wait and I do not need a solution. But this question
sticks to

my head as a conceptual problem)
Suppose there are two threads T1, T2 running concurrently:

T1()
{
While(true){
Monit.Enter(MyObjec);
{
....
}
Monitor.Exit(MyObjec);
}
}

T2()
{
While(true){
Monit.Enter(MyObjec);
{
....
}
Monitor.Exit(MyObjec);
}
}
Suppose T1 runs before T2 a little sooner.

After T1 gains the lock on MyObjec, T2 comes in and tries to get
access to

MyObjec too. Since T1 called Monitor.Enter(MyObjec) previously T2 will
be

blocked ( but as what MSDN says, it still remains in ready queue).
After a

while, T1 calls Monitor.Exit(MyObjec). So T2 can gain access to
MyObjec.

But surprisingly it cannot. Because T1 rapidly gains access to MyObjec
again.

It seems that while loop cycles too fast to let T2 gain the lock on
MyObjec. I

am not sure this is the matter of speed but I am sure that there is no
need

to call Monitor.Pulse(MyObjec) to notify T2 because T2 is still in
ready queue

(and Monitor.Pulse(MyObjec) just affects waiting queue).

What is the problem? Is this the matter of speed? Am I wrong about
the

concepts of Monitor methods?

Thanks in advance.
 
Reply With Quote
 
 
 
 
Marc Gravell
Guest
Posts: n/a
 
      16th Jun 2008
Are you sure of your test? In the following, T2 wins every time (on my
machine, at least...).

Note that "setupReady" is used to guarantee our initial state - i.e.
T1 gets the lock and releases T2 (then does a short sleep to let T2
catch up), then tries to Enter (blocks), T1 releases the lock (Exit)
and immediately re-obtains it (Enter).

Marc

using System.Threading;
using System;
using System.Diagnostics;
static class Program
{
static void Main()
{
int t1 = 0, t2 = 0;
for (int i = 0; i < 1000; i++)
{
switch (RunTest())
{
case 1: t1++; break;
case 2: t2++; break;
}
}
Console.WriteLine("{0} vs {1}", t1, t2);
Console.ReadKey();
}
class WinnerStub
{
public volatile int Winner = 0;
}
static int RunTest()
{
WinnerStub sync = new WinnerStub();
ManualResetEvent setupReady = new ManualResetEvent(false),
haveAnswer = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(delegate
{
Monitor.Enter(sync);
setupReady.Set();
Thread.Sleep(100);
// drop lock...
Monitor.Exit(sync);
Monitor.Enter(sync);
if (sync.Winner == 0)
{
sync.Winner = 1;
haveAnswer.Set();
}
Monitor.Exit(sync);
});
ThreadPool.QueueUserWorkItem(delegate
{
setupReady.WaitOne();
Monitor.Enter(sync);
if (sync.Winner == 0)
{
sync.Winner = 2;
haveAnswer.Set();
}
Monitor.Exit(sync);
});
haveAnswer.WaitOne();
Console.WriteLine("Winner: {0}", sync.Winner);
return sync.Winner;
}

}
 
Reply With Quote
 
Marc Gravell
Guest
Posts: n/a
 
      16th Jun 2008
(btw, I also tried a "while" setup like yours, but the results were
very even between the threads; so if you can post a short and complete
example that illustrates this?)
 
Reply With Quote
 
AliRezaGoogle
Guest
Posts: n/a
 
      16th Jun 2008
On Jun 16, 1:14 pm, Marc Gravell <marc.grav...@gmail.com> wrote:
> (btw, I also tried a "while" setup like yours, but the results were
> very even between the threads; so if you can post a short and complete
> example that illustrates this?)


Thank you for your attention. But you repeated what I told. My problem
is exactly what you mentioned: T2 always wins. But as you and I see in
my sample code (similarly in your code) one thread get the access and
then release it.
BUT:
Why the second thread can not get the access after that the first
thread released? As we know the second thread is on ready queue and
waiting eagerly for thread one to release!
 
Reply With Quote
 
Marc Gravell
Guest
Posts: n/a
 
      16th Jun 2008
> Thank you for your attention. But you repeated what I told. My problem
> is exactly what you mentioned: T2 always wins.


No; you said the exact opposite:

> After a while, T1 calls Monitor.Exit(MyObjec). So T2 can gain access to
> MyObjec. But surprisingly it cannot. Because T1 rapidly gains access to
> MyObjec again. It seems that while loop cycles too fast to let T2 gain the
> lock on MyObjec.


So it sounds like you are saying "T1 always wins".

> Why the second thread can not get the access after that the first
> thread released?


In my code the second thread (T2) *did* get access after the first
thread (T1) release, 100% of the time.

Hence: the best way to understand the difference is for you to post
something short but *complete* that demostrates what you are seeing.
Threading is one of those areas where the devil is *really* in the
detail.

Marc
 
Reply With Quote
 
AliRezaGoogle
Guest
Posts: n/a
 
      16th Jun 2008
On Jun 16, 2:25 pm, Marc Gravell <marc.grav...@gmail.com> wrote:
> > Thank you for your attention. But you repeated what I told. My problem
> > is exactly what you mentioned: T2 always wins.

>
> No; you said the exact opposite:
>
> > After a while, T1 calls Monitor.Exit(MyObjec). So T2 can gain access to
> > MyObjec. But surprisingly it cannot. Because T1 rapidly gains access to
> > MyObjec again. It seems that while loop cycles too fast to let T2 gain the
> > lock on MyObjec.

>
> So it sounds like you are saying "T1 always wins".
>
> > Why the second thread can not get the access after that the first
> > thread released?

>
> In my code the second thread (T2) *did* get access after the first
> thread (T1) release, 100% of the time.
>
> Hence: the best way to understand the difference is for you to post
> something short but *complete* that demostrates what you are seeing.
> Threading is one of those areas where the devil is *really* in the
> detail.
>
> Marc


Marc,
You are right and wrong!.
What I said in the first post is what I expected but never happened.
It is the sequence (which after reading MSDN) I expected but never
this ideal situation came true. I am investigating the reason. So:

1- Your result is true and exactly like me.
2- What I posted in the first post was what I designed and what I
expected to happen according to MSDN.
3- What I was expecting never happened at all (like what you
reported).
4- Now I am looking for the reason.

My actual code is not too different comparing with the simple bunch of
code I posted earlier. It is clear and can tell us everything needed.
So I think there is no need to post anything more. But if you insist I
post it.
Thanks again for your attention.

 
Reply With Quote
 
Marc Gravell
Guest
Posts: n/a
 
      16th Jun 2008
> 1- Your result is true and exactly like me.

Well, I really believe that we are seeing opposite behaviour.

> 2 - What I posted in the first post was what I designed and what I
> expected to happen according to MSDN.
> 3- What I was expecting never happened at all (like what you
> reported).


And I am saying that my code demonstrates exactly what you expected
from 2 - i.e. the second thread gets the lock. I did not report the
same findings as you in 3; I reported the opposite.

But if you are content...

Marc
 
Reply With Quote
 
AliRezaGoogle
Guest
Posts: n/a
 
      16th Jun 2008
On Jun 16, 5:04 pm, Marc Gravell <marc.grav...@gmail.com> wrote:
> > 1- Your result is true and exactly like me.

>
> Well, I really believe that we are seeing opposite behaviour.
>
> > 2 - What I posted in the first post was what I designed and what I
> > expected to happen according to MSDN.
> > 3- What I was expecting never happened at all (like what you
> > reported).

>
> And I am saying that my code demonstrates exactly what you expected
> from 2 - i.e. the second thread gets the lock. I did not report the
> same findings as you in 3; I reported the opposite.
>
> But if you are content...
>
> Marc


The second thread gets the lock but never releases it. Thread one
never gets the lock. Thats the problem.
Despite of which thread we are talking about, one thread always gets
the lock and never releases it. Why?
 
Reply With Quote
 
Marc Gravell
Guest
Posts: n/a
 
      16th Jun 2008
I think I may have confused you with the code. My example was to
contradict your specific claim that T2 never got the lock. With 2
threads running parallel, timing is important, but it isn't true that
one thread always keeps the lock; for example (going back to the
"while" example) I get pretty balanced results as follows:

T2: 46207
T1: 53794

With the code as below; this is two threads contending over a singel
lock, each incrementing a local counter, with 100k iterations (give-or-
take 1). Individual runs might be less balanced (or more balanced)
depending on what the OS is doing, the number of cores available,
karma, etc - but I would not expect to see 100k vs 0, or 0 vs 100k.

Marc

using System.Threading;
using System;
static class Program
{
static void Main()
{
ThreadPool.QueueUserWorkItem(DoWork, "T1");
ThreadPool.QueueUserWorkItem(DoWork, "T2");
Thread.Sleep(500); // let T1 & T2 get to evt.WaitOne
evt.Set();
Console.ReadKey();
}
static readonly ManualResetEvent evt = new
ManualResetEvent(false);
static readonly object sync = new object();
static int tally = 100000;
static void DoWork(object name)
{
int counter = 0;
evt.WaitOne(); // start both at the same time...
while (true)
{
Monitor.Enter(sync);
counter++;
Monitor.Exit(sync);

if(Interlocked.Decrement(ref tally) <= 0) break;
}
Console.WriteLine("{0}: {1}", name, counter);
}
}
 
Reply With Quote
 
Marc Gravell
Guest
Posts: n/a
 
      16th Jun 2008
And just in case the extra time for the Interlocked.Decrement was
changing things, I moved that inside the lock - but the behaviour is
still the same; updated "DoWork" follows, typical results:

T2: 53158
T1: 46843

static void DoWork(object name)
{
int counter = 0;
evt.WaitOne(); // start both at the same time...
while (true)
{
Monitor.Enter(sync);
counter++;
if (Interlocked.Decrement(ref tally) <= 0)
break;
Monitor.Exit(sync);
}
// broke while keeping the lock
Monitor.Exit(sync);
Console.WriteLine("{0}: {1}", name, counter);
}
 
Reply With Quote
 
 
 
Reply

Thread Tools
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
why use Monitor.Enter...Monitor.Exit insted of lock(object9 Tony Johansson Microsoft C# .NET 3 15th May 2010 10:31 PM
Monitor.Enter/Exit Question =?Utf-8?B?UnVkaQ==?= Microsoft C# .NET 3 9th Feb 2006 06:15 PM
Difference between Monitor.Enter/Monitor.Wait and AutoResetEvent.W =?Utf-8?B?TG9yZW56bw==?= Microsoft Dot NET Framework 1 24th Nov 2005 02:55 PM
RE: Monitor.Exit and Monitor.Wait not documented correctly =?Utf-8?B?YXNhbmZvcmQ=?= Microsoft Dot NET Framework 9 2nd Dec 2004 12:43 AM
Question about boxing and using Monitor::Enter / Monitor::Exit. Ken Varn Microsoft VC .NET 5 10th Jun 2004 04:49 PM


Features
 

Advertising
 

Newsgroups
 


All times are GMT +1. The time now is 10:24 AM.