Synchronization Events and Wait Handles in C#


Introduction

In my previous article we have discussed the following Synchronization techniques:

  • lock    : Ensures just one thread can access a resource, or section of code.
  • Mutex : Ensures just one thread can access a resource, or section of code. Can be used to prevent multiple instances of an application from starting.
  • Semaphore :Ensures not more than a specified number of threads can access a resource, or section of code.

In this article I will discribe a Must Inherit type class,WaitHandle. WaitHandle provides a class definition for three other classes, Mutex ManualResetEvent and AutoResetEvent, and provides means for your own objects to inherit synchronization functionality. These objects allow threads to wait until classes derived from WaitHandle are signaled. The WaitHandle derived classes add functionality over Monitor in that threads can be programmed to wait until multiple classes are signaled. Of course, along with more power and flexibility comes more work and chance of problems.

AutoResetEvent

This acts like a turnstile (Moving Door) which lets one at a time. When a thread hits WaitOne(), it waits till some other thread calls set(). An AutoResetEvent gets reset automatically once the waiting thread observes the event is signalled (set).  Apart from this being convenient if you are reusing the event multiple times, it has a practical application: if there are are multiple threads waiting on an auto-reset event, only one of them will wake up when the event gets set.  As a waiting thread, if you observe that you have woken up because an auto-reset event you were waiting on became signalled, then you can know that no other thread waiting on that same event would have woken up.

The AutoResetEvent class can be compared to the Monitor. Pulse method. Imagine it as a tollbooth. Each car has to pay to go through, the signal, and then the gate closes behind the car when it es making the next car in line pay again. The AutoResetEvent class is like this. It automatically goes back to unsignaled after being signaled and a thread goes through, just like Monitor. PulseManualResetEvent can be described as a water hose, once open it lets everything through until you close it yourself.

AutoResetEvent allows threads to communicate with each other by signaling. Typically, this communication concerns a resource to which threads need exclusive access. We can control the initial state of an AutoResetEvent by ing a Boolean value to the constructor,true if the initial state is signaled and false otherwise.

AutoResetEvent can also be used with the static

  • WaitAll
  • WaitAny methods.

I have put together a simple console application to demonstrate this class.

using System;
using System.Threading;
namespace AutoResetEventIN
{
class Process
    {
        AutoResetEvent auto;
    Process()
    {
         auto  =  new AutoResetEvent(false);
         Thread t1 = new Thread(new ThreadStart(akshay));
         Thread t2 = new Thread(new ThreadStart(csharpcorner));
         t1.Start();
         t2.Start();
         auto.Set();
         Thread.Sleep(1000);
         auto.Set();
     }
    void akshay()
    {
        auto.WaitOne();
        for (int i = 0; i < 10; i++)
        {
            Thread.Sleep(500);
            Console.WriteLine("Akshay Teotia");
        }
    }
    void csharpcorner()
    {
        auto.WaitOne();
        for (int i = 0; i < 10; i++)
        {
            Thread.Sleep(500);
            Console.WriteLine("csharpcorner.com");
        }
    }
        static void Main(string[] args)
        {
         Process p = new  Process();
         Console.Read();
        }
    }
}

Output

autoresetevent.jpg

ManualResetEvent

ManualResetEvent allows threads to communicate with each other by signaling. Typically, this communication concerns a task which one thread must complete before other threads can proceed. This is like a gate which lets more than one at a time. When a thread hits WaitOne(), it waits till someother thread calls Set().

A ManualResetEventis useful if you want to wake up a bunch of threads with a single event.  It's useful for things like termination events where you don't want to reset the event just because you observed it signalled.  If the meaning of the event is more like a flag, then you can observe the flag without changing its state back to unsignalled.

When a thread begins an activity that must complete before other threads proceed, it calls Reset to put ManualResetEvent in the non-signaled state. This thread can be thought of as controlling the ManualResetEvent. Threads that call WaitOne() on the ManualResetEvent will block, awaiting the signal. When the controlling thread completes the activity, it calls Set to signal that the waiting threads can proceed. All waiting threads are released.

Once it has been signaled, ManualResetEvent remains signaled until it is manually reset. That is, calls to WaitOne()return immediately. Like AutoResetEvent  we can control the initial state of the ManualResetEvent by ing a Boolean value to the constructor, true if the initial state is signaled and false  otherwise.

ManualResetEvent can also be used with the  static WaitAll() and WaitAny() methods.

I have put together a simple console application to demonstrate this class.

using System;
using System.Threading;
namespace ManualResetEventIn
{
    class MyThread
    {
        public Thread th;
        ManualResetEvent manualResetEvent;
        public MyThread(string name, ManualResetEvent e)
        {
            th = new Thread(this.run);
            th.Name = name;
            manualResetEvent = e;
            th.Start();
        }
        void run()
        {
            Console.WriteLine("Inside thread " + th.Name);
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine(th.Name);
                Thread.Sleep(50);
            }
            Console.WriteLine(th.Name + " Done!");
            manualResetEvent.Set();
        }
    }
     class MainClass
    {
        public static void Main()
        {
            ManualResetEvent evtObj = new ManualResetEvent(false);
            MyThread myThread = new MyThread("Event Thread 1", evtObj);
            Console.WriteLine("Main thread waiting for event.");
            // Wait for signaled event.
            evtObj.WaitOne();
            Console.WriteLine("Main thread received first event.");
            evtObj.Reset();
            myThread = new MyThread("Event Thread 2", evtObj);
            // Wait for signaled event.
            evtObj.WaitOne();
            Console.WriteLine("Main thread received second event.");
            Console.Read();
        }
    }
}

Output

Manualresetevent.jpg


Similar Articles