WaitHandle.WaitAll Method (array<WaitHandle[], TimeSpan)
Microsoft Silverlight will reach end of support after October 2021. Learn more.
Waits for all the elements in the specified array to receive a signal, using a TimeSpan value to specify the time interval.
Namespace: System.Threading
Assembly: mscorlib (in mscorlib.dll)
Syntax
'Declaration
Public Shared Function WaitAll ( _
waitHandles As WaitHandle(), _
timeout As TimeSpan _
) As Boolean
public static bool WaitAll(
WaitHandle[] waitHandles,
TimeSpan timeout
)
Parameters
- waitHandles
Type: array<System.Threading.WaitHandle[]
An array that contains the objects for which the current instance will wait. This array cannot contain multiple references to the same object.
- timeout
Type: System.TimeSpan
A TimeSpan that represents the number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds, to wait indefinitely.
Return Value
Type: System.Boolean
true when every element in waitHandles has received a signal; otherwise, false.
Exceptions
Exception | Condition |
---|---|
ArgumentNullException | The waitHandles parameter is nulla null reference (Nothing in Visual Basic). -or- One or more of the objects in the waitHandles array is nulla null reference (Nothing in Visual Basic). |
ArgumentException | The waitHandles array contains elements that are duplicates. -or- waitHandles is an array with no elements. |
NotSupportedException | The number of objects in waitHandles is greater than the system permits. |
ArgumentOutOfRangeException | timeout is a negative number other than -1 milliseconds, which represents an infinite time-out. -or- timeout is greater than Int32.MaxValue . |
Remarks
If timeout is zero, the method does not block. It tests the state of the wait handles and returns immediately.
The WaitAll method returns when the wait terminates, either when all the handles are signaled or when a time-out occurs. On some implementations, if more than 64 handles are passed, a NotSupportedException is thrown. If the array contains duplicates, the call will fail.
The maximum value for timeout is Int32.MaxValue.
If you call this method from a single-threaded apartment, and waitHandles contains more than one wait handle, the method deadlocks.
Platform Notes
Silverlight for Windows Phone
WaitAll is present but not supported in Silverlight for Windows Phone.
Examples
The following code example shows how to use this overload of the WaitAll method to report progress while waiting for the first of several threads to finish. It also demonstrates the corresponding overload of the WaitAny method.
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(array<WaitHandle[], TimeSpan) 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(array<WaitHandle[], TimeSpan) 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.
Note: |
---|
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.
Note: |
---|
To run this example, see Building Examples That Use a Demo Method and a TextBlock Control. |
Imports System.Threading
' The following imports simplify the supporting code; they are not required for
' WaitHandle:
Imports System.Windows.Controls
Imports System.Windows.Input
Imports System.ComponentModel
Public Class Example
Private Shared outputBlock As TextBlock
Public Shared Sub Demo(ByVal outputBlock As TextBlock)
Example.outputBlock = outputBlock
Example.outputBlock.Text = "Click to start the demo."
AddHandler outputBlock.MouseLeftButtonUp, AddressOf MouseUpStart
End Sub
Private Shared Sub MouseUpStart(ByVal sender As Object, ByVal e As MouseEventArgs)
' Replace the startup mouse button handler with a handler that
' displays a message.
RemoveHandler outputBlock.MouseLeftButtonUp, AddressOf MouseUpStart
AddHandler outputBlock.MouseLeftButtonUp, AddressOf MouseUp
outputBlock.Text = _
"Demo is running. The BackgroundWorker waits for the first subtask to complete," & vbLf _
& "then waits for all subtasks to complete and produces a report." & vbLf _
& "Click here at any time to show that the user interface is responsive." & vbLf
Dim worker As New System.ComponentModel.BackgroundWorker
AddHandler worker.DoWork, AddressOf DoWork
worker.WorkerReportsProgress = True
AddHandler worker.ProgressChanged, AddressOf Progress
AddHandler worker.RunWorkerCompleted, AddressOf Completed
worker.RunWorkerAsync()
End Sub
' The only purpose of this mouse button handler is to show that the user
' interface is responsive while the background tasks are running.
'
Private Shared Sub MouseUp(ByVal sender As Object, ByVal e As MouseEventArgs)
outputBlock.Text &= vbLf & "Mouse clicked." & vbLf
End Sub
Private Shared Sub DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)
' Divide the "work" into three parts, and queue three tasks to run on
' threadpool threads. Provide random data for each task.
Dim r As New Random()
' Keep a list of subtasks and a list of their ManualResetEvent objects.
Dim subtasks As New System.Collections.Generic.List(Of Subtask)
Dim finished As New System.Collections.Generic.List(Of WaitHandle)
For i As Integer = 1 To 3
Dim task As New Subtask(i, 3000 + r.Next(4000))
subtasks.Add(task)
finished.Add(task.Finished)
ThreadPool.QueueUserWorkItem(AddressOf task.DoSubtask)
Next
' 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.
Dim waitHandles() As WaitHandle = finished.ToArray()
Dim index As Integer = 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, New TimeSpan(0, 0, 0, 0, 250))
worker.ReportProgress(1)
End While
' 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 Not WaitHandle.WaitAll(waitHandles, New TimeSpan(0, 0, 0, 0, 250))
' If the WaitAll timed out, show progress.
worker.ReportProgress(3)
End While
' Generate a report and return it as the result.
Dim first As Subtask = subtasks(index)
Dim total As Double = 0.0
For Each task As Subtask In subtasks
total += task.Result.TotalMilliseconds
Next task
e.Result = String.Format( _
"Task {0} was the first to complete, with a duration of {1} seconds." _
& vbLf & "The total duration of all tasks was {2} seconds." & vbLf, _
first.SubtaskNumber, _
first.Result.TotalMilliseconds / 1000, _
total / 1000)
End Sub
Private Shared Sub Progress(ByVal sender As Object, ByVal e As ProgressChangedEventArgs)
If e.ProgressPercentage = 2 Then
outputBlock.Text &= vbLf & "First subtask is complete." & vbLf
Else
outputBlock.Text &= "."
End If
End Sub
Private Shared Sub Completed(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)
RemoveHandler worker.DoWork, AddressOf DoWork
RemoveHandler worker.ProgressChanged, AddressOf Progress
RemoveHandler worker.RunWorkerCompleted, AddressOf Completed
outputBlock.Text &= vbLf & e.Result & vbLf & "To repeat the demo, refresh the page."
End Sub
End Class
Class Subtask
' Signal this ManualResetEvent when the task is finished.
Friend Finished As New ManualResetEvent(False)
Friend SubtaskNumber As Integer
Friend Result As TimeSpan
Private data As Integer
Friend Sub New(ByVal number As Integer, data As Integer)
SubtaskNumber = number
Me.data = data
End Sub
Friend Sub DoSubTask(ByVal state As Object)
Dim start As DateTime = DateTime.Now
Thread.Sleep(data)
' Return a TimeSpan that represents the duration of the task.
Result = DateTime.Now - start
Finished.Set()
End Sub
End Class
' 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.
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, new TimeSpan(0, 0, 0, 0, 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, new TimeSpan(0, 0, 0, 0, 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.
*/
Version Information
Silverlight
Supported in: 5, 4, 3
Silverlight for Windows Phone
Supported in: Windows Phone OS 7.1, Windows Phone OS 7.0
XNA Framework
Supported in: Xbox 360, Windows Phone OS 7.0
Platforms
For a list of the operating systems and browsers that are supported by Silverlight, see Supported Operating Systems and Browsers.