dotgnu-general
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: [DotGNU]Monitor weirdness


From: Thong (Tum) Nguyen
Subject: RE: [DotGNU]Monitor weirdness
Date: Thu, 6 May 2004 14:59:25 +1200

Hi Russell,

I'm not convinced your MonitorAbortDuringWait MonitorInterrup* tests are
accurate.  Your test tests to see if a waiting thread that is aborted
reaquires the lock that it was waiting on.  By my tests, MS.NET does not
require that a thread reaquire a lock.  It does the "pretend" reaquire thing
where Wait is allowed to exit even though the monitor hasn't been aquired.
It also lets the thread call an appropriate number of "Exits" even though
the thread doesn't really own the lock.

Is this correct behaviour?  I don't think so.  Java doesn't allow a thread
to be interrupted if it can't reaquire the lock it needs to exit wait with a
consistant state.  Java's behaviour with stop (java's equivalent of abort)
seems to be that it allows the thread to exit wait without aquiring the lock
as well.  I would like to point out now that Sun wasn't being stupid when
the depreciated Thread.stop.

BTW, I'm still looking over your code.  I'm integrating some of your ideas
with the existing code.  I still believe that the current algorithm is
faster and by my tests, it can be 4-10 times faster (though in typical
desktop apps it may not make too much difference).  The current algorithm is
very fast when the monitor is uncontested and doesn't require all those
"global locks" you mentioned except for one compare and exchange.  On most
platforms where the CAX is optimised, Monitor.Enter will require no context
switches to the kernel because it never has to call ILWaitMonitorTryEnter
(which uses kernel level locks).  There are a lot of good ideas like not
incrementing monitor->waiters with InterlockedIncrement if
InterlockedIncrement is implemented using global locks.  I've decided that
putting monitors on the GC heap is a good idea.  If a lock is entered
without being exited before it gets GC-ed then the monitor will leak unless
it is GC allocated.  The currently implementation of ILWaitMutexClose
doesn't allow mutexes to close while still being owned so your
implementation (without the fixes) leaks as well.  I also still like thread
local free lists for monitors -- combined with the current algorithm it
gives good performance.  Leaks can be prevented by limiting the free list to
a reasonable number of monitors (32?).  Keeping count the number of monitors
(etc) on the list will be fast and lock free because the lists are
thread-local.

FYI, the reason the current monitor implementation failed 5 tests instead of
3 is because Monitor.Wait assumed that the monitor is only reclaimed the
call to ILWaitMonitorWait succeeds without being aborted or interrupted.  If
there is an abort or interrupt request it assumes that the monitor hasn't
been reaquired.  As mentioned above, the correct behaviour is ambiguous but
I'm leaning towards the Sun's implementation rather than Microsoft's (it's
also easier to implement ;-)).

Anyway, try the following program (put a break point in the
ThreadInterruptedException handler) and cry like I did.  I'd be pretty keen
to meet with you on IRC and chat about threading issues further...

using System;
using System.Threading;

public class Test2
{
        Thread thread1, thread2;
        
        public void Run1()
        {
                Thread.Sleep(2000);
                
                lock (this)
                {
                        Monitor.Pulse(this);
                        thread2.Interrupt();
                        
                        Thread.Sleep(50000);
                }
                
                Console.WriteLine("1 Released Lock");
        }
        
        public void Run2()
        {
                Monitor.Enter(this);
                {
                        try
                        {
                                Monitor.Wait(this);

                        }
                        catch (ThreadInterruptedException)
                        {
                                Console.WriteLine("Interrupted!");
                        }

                        Console.WriteLine("Thread 2");
                }
        }

        public void Go()
        {
                thread1 = new Thread(new ThreadStart(Run1));
                thread2 = new Thread(new ThreadStart(Run2));
                
                thread1.Start();
                thread2.Start();
        }
                
        public static void Main()
        {
                new Test2().Go();
        }
}


Regards,

^Tum

> -----Original Message-----
> From: Russell Stuart [mailto:address@hidden
> Sent: Wednesday, 5 May 2004 9:00 p.m.
> To: Thong (Tum) Nguyen
> Cc: address@hidden; 'Russell Fitchett'
> Subject: RE: [DotGNU]Monitor weirdness
> 
> On Wed, 2004-05-05 at 18:28, Thong (Tum) Nguyen wrote:
> > It doesn't do it if you've got the debugger attached (ahhh!).  Try
> running
> > it without the debugger.
> 
> Indeed, you are correct.  I second the ahhh!.  For now I am
> going to pretend I didn't see it.  It must be a bug.
> 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]