Monitor.Pulse & Wait - Unexpected behavior

http://www.codeproject.com/Articles/28785/Thread-synchronization-Wait-and-Pulse-demystified

Queues:

The finished line is a collection of threads awaiting a special castle. Another queue is introduced in the methods of Monitor.Wait: the wait queue. This is necessary because waiting for a pulse is different from waiting for a block. Like the finished queue, the waiting queue is FIFO.

Recommended Template:

These queues can lead to unexpected behavior. When an impulse occurs, the head of the wait queue is freed and added to the finished queue. However, if there are other threads in the finished queue, they will receive a lock before the thread is released. This is a problem because a thread that acquires a lock can change the state that the pulse thread is dependent. The solution is to use the condition inside the lock statement for a while

* Q = Queue.

, , Pulse, 2 . -, Q Q. -, ( , ) Ready Q, ; , (, Q , - Q).

, while Monitor.Wait, ( - , , Q )?

. , Monitor.Pulse.

. while Monitor.Wait

:

class Program
{
    static Queue<int> queue = new Queue<int>();
    static object someMonitor = new object();

    static void Main(string[] args)
    {
        Thread Thread1 = new Thread(WorkAlltheTime);
        Thread1.Name = "Thread1";
        Thread Thread2 = new Thread(WorkAlltheTime);
        Thread2.Name = "Thread2";
        Thread Thread3 = new Thread(WorkOnce);
        Thread3.Name = "Thread3";
        Thread1.Start();
        Thread2.Start();
        Thread.Sleep(1000);
        Thread3.Start();
        Console.ReadLine();
    }

    static void WorkAlltheTime()
    {
        Console.WriteLine("Came in to Ready Q: " + Thread.CurrentThread.Name);
        lock (someMonitor)
        {
            Console.WriteLine("Came out from Ready Q: " + Thread.CurrentThread.Name);
            // Broken!
            while (queue.Count == 0)
            {
                Console.WriteLine("Came in to Waiting Q: " + Thread.CurrentThread.Name);
                Monitor.Wait(someMonitor);
                Console.WriteLine("Came out from Waiting Q: " + Thread.CurrentThread.Name);
            }
            queue.Dequeue();
            Console.WriteLine("Thread: "+Thread.CurrentThread.Name+" Pulled Out");
        }
    }

    static void WorkOnce()
    {
        lock (someMonitor)
        {
            queue.Enqueue(1);
            Monitor.Pulse(someMonitor);
        }
    }   
}
+5
1

, / - Pulse , , , . :

Foo item;
lock(someMonitor)
{
    while (queue.Count == 0)
    {
        Monitor.Wait(someMonitor);
    }
    item = queue.Dequeue();
}
// Use the item

, while, :

Foo item;
lock(someMonitor)
{
    // Broken!
    if (queue.Count == 0)
    {
        Monitor.Wait(someMonitor);
    }
    item = queue.Dequeue();
}
// Use the item

, , ... (, , ).

, , , , ... , , . if, , , , .

while , , .

+9

All Articles