Pulse vs PulseAll
Pulse : Notifies a thread in the waiting queue of a change in the locked object\’s state.
PulseAll : Notifies all waiting threads of a change in the object\’s state.
We have to know waiting queue and ready queue in order to understand multi-thread and lock. All threads in ready queue have chances to be executed, and all threads in waiting queue must enter ready queue before execution. When we call Monitor.Wait(), the thread will step into waiting queue and realse its lock. Simultaneously, a single thread will be moved to ready queue if Monitor.Pulse() is called, or all threads will be done if PulseAll() is called. In the later scenario, all threads have chance to run. But in multi-thread programming, when a thread gets a chance, it will try to get a lock in our code generally, then other threads related to that lock cannot go on. This is also the reason why a few people don\’t understand their difference. Souce code is the best way to make an explanation.
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Collections.Specialized;
namespace PulseVsPulseAll
{
/**//// <summary>
/// The order of this program is to show difference between Pulse and PulseAll
/// </summary>
class Program
{
public static StringCollection list = new StringCollection();
static void Main(string[] args)
{
Thread t1 = new Thread(new ThreadStart(Fun1));
t1.Name = “t1“;
Thread t2 = new Thread(new ThreadStart(Fun2));
t2.Name = “t2“;
int count = 0;
Console.WriteLine(“Press Enter to Start“);
Console.ReadLine();
t1.Start();
t2.Start();
while (true)
{
Thread.Sleep(3000);
count++;
string hotdog = count.ToString() + “*“ + “hotdog“;
Console.WriteLine();
Console.WriteLine(“Producer: “+hotdog);
try
{
Monitor.Enter(list);
list.Add(hotdog);
Monitor.PulseAll(list); // Try Monitor.PulseAll(list); which will induce other codes to throw exception,
// because it will notify all waiting threads binding to list.
}
finally
{
Monitor.Exit(list);
}
}
t1.Join();
t2.Join();
Console.ReadLine();
}
public static void Fun1()
{
while (true)
{
if (list.Count == 0)
{
lock (list)
{
Monitor.Wait(list);
Console.WriteLine(“Fun1#“ + “Released“);
}
}
else
{
Thread.Sleep(1000);
string hotdog = list[0];
list.RemoveAt(0);
Console.WriteLine(“Fun1“ + “#“ + hotdog);
}
}
}
public static void Fun2()
{
while (true)
{
if (list.Count == 0)
{
lock(list)
{
Monitor.Wait(list);
Console.WriteLine(“Fun2#“ + “Released“);
}
}
else
{
Thread.Sleep(1000);
string hotdog = list[0];
list.RemoveAt(0);
Console.WriteLine(“Fun2“ + “#“ + hotdog);
}
}
}
}
}
The code is urgly, but can explain the problem well. If we cover the entire “if” branch code In Fun1() and Fun2 with “lock”, it won\’t be direct to show the question.
When the main thread creates a hotdog, it will notify one of the current wainting threads in waiting queue to enter ready queue and run, it can work well. But when we take place of Pulse() with PulseAll(), both of the current waiting threads will get chance to run, and will generate race condition. In this program, it will throw an exception, because both threads fetch a hotdog, one of them will fail.
Practise to improve English.