none
When and why would one use the AutoResetEvent over ManualResetEvent? RRS feed

  • Question

  • Hi all,

    I am trying to understand the need and essence of the AutoResetEvent. Can anyone give me an example where only a AutoResetEvent can be used and ManualResetEvent cannot be used?

    Also I have read that when the ManualResetEvent is Set(signaled state) then all the waiting threads get the go ahead. All the waiting threads means the threads which were made to wait by calling the WaitOne() method on the manualResetEvent object which is Set or all the waiting threads in general.
    Tuesday, January 26, 2010 2:04 PM

Answers

  • Imagine that you have a number of threads running, all of which want to print something at some point, to the one printer that you have.
    You could use an auto reset event to serialise access to that printer so that only one of the threads has access to it at once.

    Some pseudocode might be:

    // Print() method called by multiple threads.
    // "printerGuard" is the name of an autoreset event, created elsewhere and shared by all threads.

    void Print(PrintJob printJob)
    {
          printerGuard.WaitOne();
          // If we reach here, we have sole access to the printer.
          DoPrint(printJob);   // Actually do the print.
          printerGuard.Set(); // Setting this allows one other thread to gain access to the printer.
    }
    Tuesday, January 26, 2010 4:48 PM

All replies

  • 1- Using AutoResetEvent or ManualResetEvent is based on what you want your threads to do.
    A ManualResetEvent will release all the threads waiting on the handle while an AutoResetEvent will release one of the waiting threads.
    For example, if the threads are waiting to write in a file, you want them to run one after the other, so you need to use an AutoResetEvent to ensure that the WaitHandle is reset after one thread is released.

    2- The released threads are only those waiting on that particular WaitHandle object.

    Tuesday, January 26, 2010 3:22 PM
  • (cross posted )

    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.

    A manual reset event is 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.
    Tuesday, January 26, 2010 3:49 PM
  • An AutoResetEvent is like a turnstyle that only lets one person through at once.
    A ManualResetEvent is like a gate that when opened lets everyone through at once.
    Tuesday, January 26, 2010 4:09 PM
  • For example which you have mentioned for the usage of autoResetEvent, can I achieve the same by using multiple different manualResetEvent?

    Actually if I do this i am indeed simulating the autoResetEvent except for the fact that I don't reset the state when the waiting thread wakes up.

    Am I right?

    Can anyone please share a code snippet which shows how autoResetEvent is advantageous than manualResetEvent?
    Tuesday, January 26, 2010 4:11 PM
  • Thanks Wyck,

    Your answer for when to use autoResetEvent was kind of convincing but still it would be great if you share a code snippet showing clearly the advantage of the autoResetEvent over the manualResetEvent.
    Tuesday, January 26, 2010 4:14 PM
  • Matthew,

    I know the difference between the two, I am trying to understand and find a situation where autoResetEvent would be a better choice as compared to manualResetEvent.

    Please share a code snippet showing same.

    I am still searching for a convincing example. Every example which I find, I feel that it could have been achieved by using manualResetEvent(one or more).

    Please help me
    Tuesday, January 26, 2010 4:18 PM
  • Imagine that you have a number of threads running, all of which want to print something at some point, to the one printer that you have.
    You could use an auto reset event to serialise access to that printer so that only one of the threads has access to it at once.

    Some pseudocode might be:

    // Print() method called by multiple threads.
    // "printerGuard" is the name of an autoreset event, created elsewhere and shared by all threads.

    void Print(PrintJob printJob)
    {
          printerGuard.WaitOne();
          // If we reach here, we have sole access to the printer.
          DoPrint(printJob);   // Actually do the print.
          printerGuard.Set(); // Setting this allows one other thread to gain access to the printer.
    }
    Tuesday, January 26, 2010 4:48 PM
  • Thanks Matthew,

    That is very convincing.
    Tuesday, January 26, 2010 5:03 PM
  • Here's an example I wrote that is based off an MSDN sample.  The sample uses both Auto and Manual reset events.  I demonstrate how picking AutoEventReset causes the code to fail.  The fix is commented out.
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.IO;
    using System.Diagnostics;
    using System.Timers;
    using System.Threading;
    using System.IO.Packaging;
    using System.Text.RegularExpressions;
    
    using System.Collections;
    
    namespace ConsoleApplication2
    {
        class Program
        {
            static void Main(string[] args)
            {
                Calculate calc = new Calculate(true);//pass true for AutoResent event (it will fail).  False for ManuelResetEvent
                Console.WriteLine("Result = {0}.", calc.Result(234).ToString());
                Console.WriteLine("Result = {0}.", calc.Result(55).ToString());
            }
    
        }
        class Calculate
        {
            bool UseAutoResetEvent;
            double baseNumber, firstTerm, secondTerm, thirdTerm;
            AutoResetEvent[] autoEvents;
            ManualResetEvent manualEvent;
            AutoResetEvent autoReplace;
    
            // Generate random numbers to simulate the actual calculations.
            Random randomGenerator;
    
            public Calculate(bool _useAutoResetEvent)
            {
                autoEvents = new AutoResetEvent[] {new AutoResetEvent(false), new AutoResetEvent(false), new AutoResetEvent(false)};
                UseAutoResetEvent = _useAutoResetEvent;
                if (UseAutoResetEvent)
                    autoReplace = new AutoResetEvent(false);
                else
                    manualEvent = new ManualResetEvent(false);
            }
    
            void CalculateBase(object stateInfo)
            {
                baseNumber = randomGenerator.NextDouble();
                Thread.Sleep(1000);
                // Signal that baseNumber is ready.
                if (UseAutoResetEvent)
                    autoReplace.Set();
                else
                    manualEvent.Set();
            }
    
            // The following CalculateX methods all perform the same
            // series of steps as commented in CalculateFirstTerm.
    
            void CalculateFirstTerm(object stateInfo)
            {
                // Perform a precalculation.
                double preCalc = randomGenerator.NextDouble();
    
                // Wait for baseNumber to be calculated.
                if (UseAutoResetEvent)
                {
                    autoReplace.WaitOne();
                    Console.WriteLine("CalculateFirstTerm executed.  Now we are stuck forever.");
                    //autoReplace.Set();//Uncomment me to fix
                }
                else
                {
                    manualEvent.WaitOne();
                }
                // Calculate the first term from preCalc and baseNumber.
                firstTerm = preCalc * baseNumber * randomGenerator.NextDouble();
    
                // Signal that the calculation is finished.
                autoEvents[0].Set();
            }
    
            void CalculateSecondTerm(object stateInfo)
            {
                double preCalc = randomGenerator.NextDouble();
                if (UseAutoResetEvent)
                {
                    autoReplace.WaitOne();
                    Console.WriteLine("CalculateSecondTerm executed.  Now we are stuck forever.");
                    //autoReplace.Set();//Uncomment me to fix
                }
                else
                {
                    manualEvent.WaitOne();
                }
                secondTerm = preCalc * baseNumber * randomGenerator.NextDouble();
                autoEvents[1].Set();
            }
    
            void CalculateThirdTerm(object stateInfo)
            {
                double preCalc = randomGenerator.NextDouble();
                if (UseAutoResetEvent)
                {
                    autoReplace.WaitOne();
                    Console.WriteLine("CalculateThirdTerm executed.  Now we are stuck forever.");
                    //autoReplace.Set();//Uncomment me to fix
                }
                else
                {
                    manualEvent.WaitOne();
                }
                thirdTerm = preCalc * baseNumber * randomGenerator.NextDouble();
                autoEvents[2].Set();
            }
    
            public double Result(int seed)
            {
                randomGenerator = new Random(seed);
    
                // Simultaneously calculate the terms.
                ThreadPool.QueueUserWorkItem(new WaitCallback(CalculateBase));
                ThreadPool.QueueUserWorkItem(new WaitCallback(CalculateFirstTerm));
                ThreadPool.QueueUserWorkItem(new WaitCallback(CalculateSecondTerm));
                ThreadPool.QueueUserWorkItem(new WaitCallback(CalculateThirdTerm));
    
                // Wait for all of the terms to be calculated.
                WaitHandle.WaitAll(autoEvents);
    
                // Reset the wait handle for the next calculation.
                if(UseAutoResetEvent)
                    autoReplace.Reset();
                else
                    manualEvent.Reset();
    
                return firstTerm + secondTerm + thirdTerm;
            }
        }
    
    }
    

    BrianMackey.NET
    Thursday, January 28, 2010 4:44 PM