Monitor.Wait, with timeout

  • Thread starter Thread starter Jon Shemitz
  • Start date Start date
J

Jon Shemitz

The (beta 2) dox say "The time-out ... moves the thread to the ready
queue, bypassing other threads ahead of it in the wait queue, so that
it can reacquire the lock sooner."

To me, this directly states that when I Pulse a locked object that has
threads waiting, a thread that is waiting with a timeout will be moved
to the ready queue ahead of a thread that is waiting without a
timeout. It also rather strongly implies that a thread that is about
to timeout will get priority ahead of a thread that is willing to wait
longer.

Yet, the attached program wakes waiting threads in creation order,
exactly as if a Pulse or PulseAll simply moved threads from the
waiting queue to the ready queue in the order that they entered the
waiting queue. (Run the console app from a DOS box ...)

Are the dox wrong, or am I misinterpreting my test program?

--

www.midnightbeach.com
using System;
using System.Threading;

namespace WaitPriorities
{
class Program
{
static void Main(string[] args)
{
object Lock = new object();

new Thread(new ParameterizedThreadStart(NoTimeout)).Start(Lock);
new Thread(new ParameterizedThreadStart(LongTimeout)).Start(Lock);
new Thread(new ParameterizedThreadStart(ShortTimeout)).Start(Lock);

//lock (Lock)
// Monitor.PulseAll(Lock);
lock (Lock)
Monitor.Pulse(Lock);
lock (Lock)
Monitor.Pulse(Lock);
lock (Lock)
Monitor.Pulse(Lock);
}

static void NoTimeout(object Lock)
{
lock (Lock)
{
Monitor.Wait(Lock);
Console.WriteLine("NoTimeout");
}
}

static void ShortTimeout(object Lock)
{
lock (Lock)
{
bool Locked = Monitor.Wait(Lock, 1000);
Console.WriteLine("ShortTimeout ({0})", Locked ? "Locked" : "Not locked");
}
}

static void LongTimeout(object Lock)
{
lock (Lock)
{
bool Locked = Monitor.Wait(Lock, 1500);
Console.WriteLine("LongTimeout ({0})", Locked ? "Locked" : "Not locked");
}
}
}
}
 
The threads are only moved when their wait time-out has expired.
In your sample you pulse the threads before their wait time-out have expired
so their schedule order remains unchanged. If you wait a bit before you
pulse you'll see what I mean.

new Thread(new ParameterizedThreadStart(ShortTimeout)).Start(Lock);
Thread.Sleep(2000);
lock (Lock)
Monitor.Pulse(Lock);


Or change you code like this ...

Thread.Sleep(500);
lock (Lock)
.......
}

static void NoTimeout(object Lock)
{
lock (Lock)
{
Monitor.Wait(Lock);
....
static void ShortTimeout(object Lock)
{
lock (Lock)
{
bool Locked = Monitor.Wait(Lock, 300);
....
static void LongTimeout(object Lock)
{
lock (Lock)
{
bool Locked = Monitor.Wait(Lock, 600);
....


Willy.
 
Willy Denoyette said:
The threads are only moved when their wait time-out has expired.
In your sample you pulse the threads before their wait time-out have expired
so their schedule order remains unchanged. If you wait a bit before you
pulse you'll see what I mean.

Oh, thank you! I *did* misread the docs. I thought that a false result
(a time-out) did not re-acquire the lock. I think the docs are poorly
written (that still seems the most reasonable interpretation, to me)
but I can see why Wait would always re-acquire a lock: otherwise, you
couldn't use Monitor.Wait within a C# lock() statement.
 
Back
Top