Search code examples
c#multithreadingpulse

C#: Monitor.Pulse() doesn't work


I had a problem which I reduced to this minimal test-case, and still I don't understand why doesn't it work properly. The code here is simple: the parent thread acquires a lock, then launch a child, next frees the lock by starting await on it. Then the child thread that were locked on the same lock proceeds, frees the parent, next sleeps for five seconds.

using System.Threading;
using System;
using System.IO;
using System.Diagnostics;

namespace Test
{
    class MainClass
    {
        public static void Main(string[] args)
        {
            Object waitForThrToStart = new Object();
            lock (waitForThrToStart)
            {
                new Thread(() =>
                {
                    lock (waitForThrToStart)
                    {
                        Debug.WriteLine("2. Child: free the parent");
                        Monitor.Pulse(waitForThrToStart);
                        Debug.WriteLine("3. Child: pulsed ☺ Now sleep");
                        Thread.Sleep(5000);
                        Debug.WriteLine("5. Child: time out");
                    }
                }).Start();
                Debug.WriteLine("1. Parent: waiting");
                Monitor.Wait(waitForThrToStart);
                Debug.WriteLine("4. Parent: awoke, exiting now");
            }
        }
    }
}

It is fine except that… it doesn't work. The parent freed only after five seconds, when the child exited, you may see it in output:

1. Parent: waiting
2. Child: free the parent
3. Child: pulsed ☺ Now sleep
5. Child: time out
4. Parent: awoke, exiting now

I did even try to use Monitor.PulseAll(), that didn't change anything. Also I thought perhaps for some weird reason the child got a copy of the Object, thus they're work on different variables. But I disproved it by setting a Sleep() call in parent — the child surely waited for the lock.

What is this, is that a bug? Is there any workaround?


Solution

  • You're pulsing the monitor in child, but you've also got it locked. The Wait will only return once you've released the lock in the child thread, at which point it will need to reacquire the lock before returning.