locked
Monitor.Wait/Monitor.Pulse RRS feed

  • Question

  • User1904516115 posted

    Can anyone explain Monitor.Wait/Monitor.Pulse with simple example?

    Wednesday, January 31, 2018 7:42 PM

All replies

  • User-707554951 posted

    Hi vinodkpasi

    The Wait () and Pulse () mechanisms are used for inter-thread interaction. When using the Wait () method on an object, the thread accessing the object waits until it is awakened. The Pulse () and PulseAll () methods are used to notify the waiting thread to wake up. Here's an example of how the Wait () and Pulse () methods work

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Threading;
    
    namespace WaitAndPulse
    {
        public class LockMe
        { 
        }
    
        class WaitPulse1
        {
            private int result = 0;
            private LockMe lM;
    
            public WaitPulse1()
            {
            }
    
            public WaitPulse1(LockMe l)
            {
                this.lM = l;
            }
    
            public void CriticalSection()
            {
                Monitor.Enter(this.lM);
                //Enter the Critical Section
                Console.WriteLine("WaitPulse1: Entered Thread "
                    + Thread.CurrentThread.GetHashCode());
    
                for (int i = 1; i <= 5; i++)
                {
                    Monitor.Wait(this.lM);
                    Console.WriteLine("WaitPulse1: WokeUp");
                    Console.WriteLine("WaitPulse1: Result = "
                        + result++
                        + " ThreadID "
                        + Thread.CurrentThread.GetHashCode());
                    Monitor.Pulse(this.lM);
                }
                Console.WriteLine("WaitPulse1: Exiting Thread "
                    + Thread.CurrentThread.GetHashCode());
    
                //Exit the Critical Section
                Monitor.Exit(this.lM);
            }
        }
    
        class WaitPulse2
        {
            private int result = 0;
            private LockMe lM;
    
            public WaitPulse2()
            {
            }
    
            public WaitPulse2(LockMe l)
            {
                this.lM = l;
            }
    
            public void CriticalSection()
            {
                Monitor.Enter(this.lM);
                //Enter the Critical Section
                Console.WriteLine("WaitPulse2: Entered Thread "
                    + Thread.CurrentThread.GetHashCode());
    
                for (int i = 1; i <= 5; i++)
                {
                    Monitor.Pulse(this.lM);
                    Console.WriteLine("WaitPulse2: Result = "
                        + result++
                        + " ThreadID "
                        + Thread.CurrentThread.GetHashCode());
                    Monitor.Wait(this.lM);
                    Console.WriteLine("WaitPulse2: WokeUp");
                }
                Console.WriteLine("WaitPulse2: Exiting Thread "
                    + Thread.CurrentThread.GetHashCode());
    
                //Exit the Critical Section
                Monitor.Exit(this.lM);
            }
        }
    
        public class ClassForMain
        {
            public static void Main(string[] args)
            {
                LockMe l = new LockMe();
    
                WaitPulse1 e1 = new WaitPulse1(l);
                WaitPulse2 e2 = new WaitPulse2(l);
    
                Thread t1 = new Thread(new ThreadStart(e1.CriticalSection));
                t1.Start();
    
                Thread t2 = new Thread(new ThreadStart(e2.CriticalSection));
                t2.Start();
    
                //Wait till the user enters something
                Console.ReadLine();
            }
        }
    }

    In the Main () method, we created a LockMe object. Then create two objects, WaitPulse1, WaitPulse2, and then delegate them to the thread so that the thread can call the CriticalSection () method of both objects. Note that the LockMe instances in the two objects WaitPulse1 and WaitPulse2 are different because the object reference passed to the corresponding constructor is different. After initializing the object, we create two threads, t1 and t2, and pass the respective CriticalSection () function to each of these two threads.

    Assuming WaitPulse1.CriticalSection () executes first, thread t1 enters the key part of the method and executes Monitor.Wait () in the for loop after locking the LockMe object. Due to the implementation of Monitor.Wait (), it has to wait for other threads to call the Monitor.Pulse () method (a runtime notification) to wake it up. We lock the LockMe object because we only want to have access to the shared LockMe instance for just one object at any one time.

    Note When a thread executes the Monitor.Wait () method, it temporarily releases the lock on the LockMe object so that other threads can access the LockMe object. After the thread t1 enters the wait state, the thread t2 can freely access the LockMe object. Although both threads have their own LockMe objects (WaitPulse1, WaitPulse2), they both reference the same object. Thread t2 gets the lock on the LockMe object and enters the WaitPulse2.CriticalSection () method. When it enters the for loop, it sends a run-time notification (Monitor.Pulse ()) to the thread waiting for the LockMe object (t1 in this case) and enters the wait state.

    Finally, t1 wakes up and gets LockMe lock. Thread t1 then accesses the result variable and sends a runtime notification to the thread waiting for the LockMe object (t2 in this case). So repeatedly until the for loop ends.

    You also coudl refer to the article below for full understanding:

    http://www.c-sharpcorner.com/UploadFile/1d42da/wait-and-pulse-method-in-threading-C-Sharp/

    Best regards

    Cathy

    Thursday, February 1, 2018 3:13 AM