This topic has not yet been rated - Rate this topic

WaitHandle Class

April 12, 2014

Encapsulates operating system–specific objects that wait for exclusive access to shared resources.

Namespace:  System.Threading
Assembly:  mscorlib (in mscorlib.dll)
public abstract class WaitHandle : IDisposable

The WaitHandle type exposes the following members.

  NameDescription
Protected methodWaitHandleInitializes a new instance of the WaitHandle class.
Top
  NameDescription
Public propertySafeWaitHandleGets or sets the native operating-system handle.
Top
  NameDescription
Public methodCloseWhen overridden in a derived class, releases all resources held by the current WaitHandle.
Public methodDispose()Releases all resources used by the current instance of the WaitHandle class.
Protected methodDispose(Boolean)When overridden in a derived class, releases the unmanaged resources used by the WaitHandle, and optionally releases the managed resources.
Public methodEquals(Object)Determines whether the specified Object is equal to the current Object. (Inherited from Object.)
Protected methodFinalizeAllows an object to try to free resources and perform other cleanup operations before the Object is reclaimed by garbage collection. (Inherited from Object.)
Public methodGetHashCodeServes as a hash function for a particular type. (Inherited from Object.)
Public methodGetTypeGets the Type of the current instance. (Inherited from Object.)
Protected methodMemberwiseCloneCreates a shallow copy of the current Object. (Inherited from Object.)
Public methodToStringReturns a string that represents the current object. (Inherited from Object.)
Public methodStatic memberWaitAll(WaitHandle[])Waits for all the elements in the specified array to receive a signal.
Public methodStatic memberWaitAll(WaitHandle[], Int32)Waits for all the elements in the specified array to receive a signal, using an Int32 value to specify the time interval.
Public methodStatic memberWaitAll(WaitHandle[], TimeSpan)Waits for all the elements in the specified array to receive a signal, using a TimeSpan value to specify the time interval.
Public methodStatic memberWaitAny(WaitHandle[])Waits for any of the elements in the specified array to receive a signal.
Public methodStatic memberWaitAny(WaitHandle[], Int32)Waits for any of the elements in the specified array to receive a signal, using a 32-bit signed integer to specify the time interval.
Public methodStatic memberWaitAny(WaitHandle[], TimeSpan)Waits for any of the elements in the specified array to receive a signal, using a TimeSpan to specify the time interval.
Public methodWaitOne()Blocks the current thread until the current WaitHandle receives a signal.
Public methodWaitOne(Int32)Blocks the current thread until the current WaitHandle receives a signal, using 32-bit signed integer to specify the time interval.
Public methodWaitOne(TimeSpan)Blocks the current thread until the current instance receives a signal, using a TimeSpan to specify the time interval.
Top
  NameDescription
Protected fieldStatic memberInvalidHandleRepresents an invalid native operating-system handle. This field is read-only.
Public fieldStatic memberWaitTimeoutIndicates that a WaitAny operation timed out before any of the wait handles were signaled. This field is constant.
Top

This class is typically used as a base class for synchronization objects. Classes that are derived from WaitHandle define a signaling mechanism to indicate taking or releasing access to a shared resource, but they use the inherited WaitHandle methods to block while waiting for access to shared resources. In Windows Phone, the AutoResetEvent and ManualResetEvent classes, along with their base class, EventWaitHandle, derive from WaitHandle.

Use the static methods of this class to block a thread until one or more synchronization objects receive a signal.

The following example shows how to divide work among three thread pool threads, and how to use the static WaitAny and WaitAll methods to wait until the subtasks are finished.

The example creates a BackgroundWorker that reports progress to the user interface. By using a BackgroundWorker, the example insulates the user interface thread from the effects of the WaitAny and WaitAll methods, and thus allows the user interface to remain responsive.

The BackgroundWorker runs a DoWork method that creates three tasks by using the ThreadPool.QueueUserWorkItem method, and assigns each task a random amount of work. The example defines a Subtask class to hold the data and thread procedure for each task. Each task has a ManualResetEvent, which it signals when its work is complete.

After starting the tasks, the DoWork method uses the WaitAny(WaitHandle[], Int32) method overload to wait for the shortest subtask to finish, with a 250-millisecond time-out to report progress to the user interface. The BackgroundWorker then uses the WaitAll(WaitHandle[], Int32) method overload to wait until the rest of the tasks are complete, once again with a time-out to show progress. The DoWork method then produces a report using the results from all three tasks.

NoteNote:

The shortest task is not necessarily the first to complete. The thread pool threads may not all start immediately and may not be treated equally by the scheduler.

After you start the example, it changes the mouse button event to show user clicks, demonstrating that the user interface remains responsive during the execution of the background tasks.


using System;
using System.Threading;

// The following using statements simplify the supporting code; they are not required 
// for WaitHandle:
using System.Windows.Controls;
using System.Windows.Input;
using System.ComponentModel;

public class Example
{
   private static TextBlock outputBlock;

   public static void Demo(TextBlock outputBlock)
   {
      Example.outputBlock = outputBlock;
      Example.outputBlock.Text = "Click to start the demo.";

      outputBlock.MouseLeftButtonUp += new MouseButtonEventHandler(MouseUpStart);
   }

   private static void MouseUpStart(object sender, MouseEventArgs e)
   {
      // Replace the startup mouse button handler with a handler that 
      // displays a message.
      outputBlock.MouseLeftButtonUp -= new MouseButtonEventHandler(MouseUpStart);
      outputBlock.MouseLeftButtonUp += new MouseButtonEventHandler(MouseUp);

      outputBlock.Text = 
         "Demo is running. The BackgroundWorker waits for the first subtask to complete,\n" +
         "then waits for all subtasks to complete and produces a report.\n" +
         "Click here at any time to show that the user interface is responsive.\n";

      System.ComponentModel.BackgroundWorker worker = new System.ComponentModel.BackgroundWorker();
      worker.DoWork += DoWork;
      worker.WorkerReportsProgress = true;
      worker.ProgressChanged += Progress;
      worker.RunWorkerCompleted += Completed;
      worker.RunWorkerAsync();
   }

   // The only purpose of this mouse button handler is to show that the user
   // interface is responsive while the background tasks are running.
   //
   private static void MouseUp(object sender, MouseEventArgs e)
   {
      outputBlock.Text += "\nMouse clicked.\n";
   }

   private static void DoWork(object sender, DoWorkEventArgs e)
   {
      BackgroundWorker worker = (BackgroundWorker) sender;

      // Divide the "work" into three parts, and queue three tasks to run on
      // threadpool threads. Provide random data for each task.

      Random r = new Random();
      // Keep a list of subtasks and a list of their ManualResetEvent objects.
      System.Collections.Generic.List<Subtask> subtasks = 
                                 new System.Collections.Generic.List<Subtask>();
      System.Collections.Generic.List<WaitHandle> finished = 
                                 new System.Collections.Generic.List<WaitHandle>();

      for(int i = 1; i <= 3; i++)
      {
         Subtask task = new Subtask(i, 3000 + r.Next(4000));
         subtasks.Add(task);
         finished.Add(task.Finished);
         ThreadPool.QueueUserWorkItem(task.DoSubtask);
      }


      // Wait for ANY subtask to complete, and show progress.

      // Create an array of ManualResetEvent wait handles. Each subtask will
      // signal its ManualResetEvent when it is finished.
      WaitHandle[] waitHandles = finished.ToArray();
      int index = WaitHandle.WaitTimeout;

      while (index == WaitHandle.WaitTimeout)
      {
         // Wait for any WaitHandle to be signaled. Use a timeout of 250 milliseconds 
         // to send progress reports. If a timeout occurs, WaitTimeout is returned;
         // if a WaitHandle signals, the array index of the WaitHandle is returned.
         //
         index = WaitHandle.WaitAny(waitHandles, 250);
         worker.ReportProgress(1);
      }


      // In an actual application, the result of the first subtask could be 
      // processed now. Instead, signal the user interface that the first
      // subtask is done.
      worker.ReportProgress(2);


      // Wait for ALL subtasks to complete, and show progress every 1/4 second if
      // the WaitAll times out.

      while (!WaitHandle.WaitAll(waitHandles, 250))
      {
         // If the WaitAll timed out, show progress.
         worker.ReportProgress(3);
      }


      // Generate a report and return it as the result.
      Subtask first = subtasks[index];
      double total = 0.0;

      foreach( Subtask task in subtasks )
      {
         total += task.Result.TotalMilliseconds;
      }

      e.Result = String.Format(
         "Task {0} was the first to complete, with a duration of {1} seconds.\n"
            + "The total duration of all tasks was {2} seconds.\n", 
         first.SubtaskNumber, 
         first.Result.TotalMilliseconds/1000, 
         total/1000);
   }

   private static void Progress(object sender, ProgressChangedEventArgs e)
   {
      if (e.ProgressPercentage == 2)
      {
         outputBlock.Text += "\nFirst subtask is complete.\n";
      }
      else
      {
         outputBlock.Text += ".";
      }
   }

   private static void Completed(object sender, RunWorkerCompletedEventArgs e)
   {
      BackgroundWorker worker = (BackgroundWorker) sender;
      worker.DoWork -= DoWork;
      worker.ProgressChanged -= Progress;
      worker.RunWorkerCompleted -= Completed;

      outputBlock.Text += 
         String.Format("\n{0}\nTo repeat the demo, refresh the page.", e.Result);
   }
}

class Subtask
{
   // Signal this ManualResetEvent when the task is finished.
   internal ManualResetEvent Finished = new ManualResetEvent(false);
   internal int SubtaskNumber;
   internal TimeSpan Result;
   private int data;

   internal Subtask(int number, int data)
   {
      SubtaskNumber = number;
      this.data = data;
   }

   internal void DoSubtask(object state)
   {
      DateTime start = DateTime.Now;
      Thread.Sleep(data);
      // Return a TimeSpan that represents the duration of the task.
      Result = DateTime.Now-start;
      Finished.Set();
   }
}

/* This code produces output similar to the following:

Demo is running. The BackgroundWorker waits for the first subtask to complete,
then waits for all subtasks to complete and produces a report.
Click here at any time to show that the user interface is responsive.
.....
Mouse clicked.
...........
First subtask is complete.
............
Task 3 was the first to complete, with a duration of 3.178 seconds.
The total duration of all tasks was 15.3553943 seconds.

To repeat the demo, refresh the page.
 */


Windows Phone OS

Supported in: 8.1, 8.0, 7.1, 7.0

Windows Phone

This type is thread safe.

Did you find this helpful?
(1500 characters remaining)
Thank you for your feedback
Show:
© 2014 Microsoft. All rights reserved.