in the following code example:
class Program
{
private static int counter = 0;
public static object lockRef = new object();
static void Main(string[] args)
{
var th = new Thread(new ThreadStart(() => {
Thread.Sleep(1000);
while (true)
{
Monitor.Enter(Program.lockRef);
++Program.counter;
Monitor.Exit(Program.lockRef);
}
}));
th.Start();
while (true)
{
Monitor.Enter(Program.lockRef);
if (Program.counter != 100)
{
Console.WriteLine(Program.counter);
}
else
{
break;
}
Monitor.Exit(Program.lockRef);
}
Console.Read();
}
}
Why does the while loop inside Main function does not break even if I use lock with Monitor? If I add Thread.Sleep(1) inside the Thread while everything works as expected and even without Monitor…
Is it just happening too fast that the Monitor class doesn't have enough time to lock?
NOTE: The != operator is intended. I know I can set it to < and solve the problem. What I was trying to achieve is to see it working with Monitor class and not working without it. Unfortunately it doesn't work both ways. Thanks
The first thread with the while, might get scheduled twice in a row (ie the Monitor might not be fair.)
See this related question: Does lock() guarantee acquired in order requested?
Let's assume you have 1 CPU available. This is how the execution will look like
T1 [SLEEP][INCREMENT][SLEEP][INCREMENT][SLEEP][INCREMENT][SLEEP] T2 --[L][CK][UL][L][CK][UL][L][CK][UL][L][CK][UL][L][CK][UL][L][CK][UL] CPU1 [ T2 ][T1][ T2 ][ T1 ][ T2 ][T1][ T2 ][ T1 ][ T2 ][T1]...
Where:
T1
is th threadT2
is main thread[L][CK][UL]
is lock, check, unlock - the workload of the main threadCPU1
is task scheduling for the CPU
Note a short [T1]
is a call to Thread.Sleep
. This results in the current thread yielding control immediately. This thread will not be scheduled for executing for time greater or equal to the specified milisecond parameter.
Longer [ T1 ]
is where increment in while
loop happens.
Important: T1
will not execute a single increment and then switch to another thread. This is where the problem. It will do many iterations until the current thread execution quant expires. On average you can think of execution quant ~ 10-30 mili seconds.
This is exactly supported by the output, which on my machine was
0 0 0 ... 56283 56283 56283 ... 699482 699482 699482 ...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With