Udostępnij za pośrednictwem


AutoResetEvent Class

Microsoft Silverlight will reach end of support after October 2021. Learn more.

Notifies a waiting thread that an event has occurred. This class cannot be inherited.

Inheritance Hierarchy

System.Object
  System.Threading.WaitHandle
    System.Threading.EventWaitHandle
      System.Threading.AutoResetEvent

Namespace:  System.Threading
Assembly:  mscorlib (in mscorlib.dll)

Syntax

'Declaration
<ComVisibleAttribute(True)> _
Public NotInheritable Class AutoResetEvent _
    Inherits EventWaitHandle
[ComVisibleAttribute(true)]
public sealed class AutoResetEvent : EventWaitHandle

The AutoResetEvent type exposes the following members.

Constructors

  Name Description
Public methodSupported by Silverlight for Windows PhoneSupported by Xbox 360 AutoResetEvent Initializes a new instance of the AutoResetEvent class with a Boolean value that indicates whether to set the initial state to signaled.

Top

Properties

  Name Description
Public propertySupported by Silverlight for Windows PhoneSupported by Xbox 360 SafeWaitHandle Gets or sets the native operating-system handle. (Inherited from WaitHandle.)

Top

Methods

  Name Description
Public methodSupported by Silverlight for Windows PhoneSupported by Xbox 360 Close When overridden in a derived class, releases all resources held by the current WaitHandle. (Inherited from WaitHandle.)
Public methodSupported by Silverlight for Windows PhoneSupported by Xbox 360 Dispose() Releases all resources used by the current instance of the WaitHandle class. (Inherited from WaitHandle.)
Protected methodSupported by Silverlight for Windows PhoneSupported by Xbox 360 Dispose(Boolean) When overridden in a derived class, releases the unmanaged resources used by the WaitHandle, and optionally releases the managed resources. (Inherited from WaitHandle.)
Public methodSupported by Silverlight for Windows PhoneSupported by Xbox 360 Equals(Object) Determines whether the specified Object is equal to the current Object. (Inherited from Object.)
Protected methodSupported by Silverlight for Windows PhoneSupported by Xbox 360 Finalize Allows an object to try to free resources and perform other cleanup operations before the Object is reclaimed by garbage collection. (Inherited from Object.)
Public methodSupported by Silverlight for Windows PhoneSupported by Xbox 360 GetHashCode Serves as a hash function for a particular type. (Inherited from Object.)
Public methodSupported by Silverlight for Windows PhoneSupported by Xbox 360 GetType Gets the Type of the current instance. (Inherited from Object.)
Protected methodSupported by Silverlight for Windows PhoneSupported by Xbox 360 MemberwiseClone Creates a shallow copy of the current Object. (Inherited from Object.)
Public methodSupported by Silverlight for Windows PhoneSupported by Xbox 360 Reset Sets the state of the event to non-signaled, which causes threads to block. (Inherited from EventWaitHandle.)
Public methodSupported by Silverlight for Windows PhoneSupported by Xbox 360 Set Sets the state of the event to signaled, which allows one or more waiting threads to proceed. (Inherited from EventWaitHandle.)
Public methodSupported by Silverlight for Windows PhoneSupported by Xbox 360 ToString Returns a string that represents the current object. (Inherited from Object.)
Public methodSupported by Silverlight for Windows PhoneSupported by Xbox 360 WaitOne() Blocks the current thread until the current WaitHandle receives a signal. (Inherited from WaitHandle.)

In Silverlight for Windows Phone, this member is overridden by WaitOne().

In XNA Framework, this member is overridden by WaitOne().
Public methodSupported by Silverlight for Windows PhoneSupported by Xbox 360 WaitOne(Int32) Blocks the current thread until the current WaitHandle receives a signal, using 32-bit signed integer to specify the time interval. (Inherited from WaitHandle.)
Public methodSupported by Silverlight for Windows PhoneSupported by Xbox 360 WaitOne(TimeSpan) Blocks the current thread until the current instance receives a signal, using a TimeSpan to specify the time interval. (Inherited from WaitHandle.)

Top

Remarks

AutoResetEvent enables threads to communicate with each other by signaling. Typically, this communication concerns a resource to which threads need exclusive access.

A thread waits for a signal by calling the WaitOne method on the AutoResetEvent. If the AutoResetEvent is in the non-signaled state, the thread blocks, waiting for the thread that currently controls the resource to signal that the resource is available by calling the Set method.

Calling Set signals AutoResetEvent to release a waiting thread. AutoResetEvent remains signaled until a single waiting thread is released, and then automatically returns to the non-signaled state. If no threads are waiting, the state remains signaled indefinitely.

If a thread calls WaitOne while the AutoResetEvent is in the signaled state, the thread does not block. The AutoResetEvent releases the thread immediately and returns to the non-signaled state.

Important noteImportant Note:

There is no guarantee that every call to the Set method will release a thread. If two calls are so close together that the second call occurs before a thread has been released, only one thread is released. It is as if the second call did not occur. Also, if Set is called when there are no threads waiting and the AutoResetEvent is already signaled, the call has no effect.

You can control the initial state of an AutoResetEvent by passing a Boolean value to the constructor: true if the initial state is signaled and false otherwise.

AutoResetEvent can also be used with the staticWaitAll and WaitAny methods.

For more information about thread synchronization mechanisms, see EventWaitHandle, AutoResetEvent, and ManualResetEvent and Synchronization Primitives in the conceptual documentation.

Examples

This section contains two code examples. The first example uses an AutoResetEvent to synchronize the activities of a reader thread and a writer thread. The second example demonstrates the use of AutoResetEvent and ManualResetEvent to control the interaction of multiple threads.

Example 1

The following example uses an AutoResetEvent to synchronize the activities of two threads. The first thread executes MyWriteThreadProc. It writes values to the protected resource, which is a static (Shared in Visual Basic) field named number. The second thread executes the static MyReadThreadProc method, which reads the values written by MyWriteThreadProc.

The MyReadThreadProc method waits for the AutoResetEvent. When MyWriteThreadProc calls the Set method on the AutoResetEvent, the MyReadThreadProc method reads one value. The AutoResetEvent immediately resets, so the MyReadThreadProc method waits again.

The program logic guarantees that the MyReadThreadProc method will never read the same value two times. It does not guarantee that the MyReadThreadProc method will read every value written by MyWriteThreadProc. That guarantee would require a second AutoResetEvent lock.

After each write operation, MyWriteThreadProc yields by calling the Thread.Sleep method, to give the second thread a chance to execute. Otherwise, on a single-processor computer MyWriteThreadProc would write many values between any two read operations.

The Demo method starts the two thread procedures. The threads write their output to a StringBuilder object, which is protected from concurrent access by lock statements (SyncLock statements in Visual Basic). The MyWriteThreadProc method appends the final output to the TextBlock control by using the Dispatcher property to obtain a Dispatcher object for the TextBlock, and then using the Dispatcher.BeginInvoke method to make the cross-thread call to the UI thread.

Imports System.Threading
Imports System.Text

Class Example
    Private Const numIterations As Integer = 10

    ' Create an AutoResetEvent that is initially not signaled.
    Private Shared myResetEvent As New AutoResetEvent(False)

    Private Shared number As Integer
    Private Shared running As Boolean = True
    Private Shared output As New StringBuilder()
    Private Shared outputBlock As System.Windows.Controls.TextBlock

    Public Shared Sub Demo(ByVal outputBlock As System.Windows.Controls.TextBlock)

        Example.outputBlock = outputBlock

        'Create and start the reader thread.
        Dim myReaderThread As New Thread(AddressOf MyReadThreadProc)
        myReaderThread.Name = "ReaderThread"
        myReaderThread.Start()

        'Create and start the writer thread.
        Dim myWriterThread As New Thread(AddressOf MyWriteThreadProc)
        myWriterThread.Name = "WriterThread"
        myWriterThread.Start()

    End Sub

    Shared Sub MyReadThreadProc()

        While running
            'The value will not be read until the writer has written
            ' at least once since the last read.
            myResetEvent.WaitOne()

            SyncLock output
                output.AppendLine(String.Format("{0} reading value: {1}", _
                    Thread.CurrentThread.Name, number))
            End SyncLock
        End While
    End Sub 

    Shared Sub MyWriteThreadProc()

        For i As Integer = 1 To numIterations
            SyncLock output
                output.AppendLine(String.Format("{0} writing value: {1}", _
                    Thread.CurrentThread.Name, i))
            End SyncLock

            number = i

            'Signal that a value has been written.
            myResetEvent.Set()

            'Give the Reader thread an opportunity to act.
            Thread.Sleep(1)
        Next i

        'Terminate the reader thread.
        running = False
        myResetEvent.Set()

        SyncLock output
            ' Append the output from the example to the TextBlock control,
            ' on the UI thread.
            outputBlock.Dispatcher.BeginInvoke(displayHelper, output.ToString())
        End SyncLock
    End Sub 

    ' In order to update the TextBlock object, which is on the UI thread, you must
    ' make a cross-thread call by using the Dispatcher object that is associated 
    ' with the TextBlock. The DisplayOutput helper method and its delegate, 
    ' displayHelper, are used by the BeginInvoke method of the Dispatcher object
    ' to append text to the TextBlock. 
    '
    Private Shared displayHelper As New Action(Of String)(AddressOf DisplayOutput)
    Private Shared Sub DisplayOutput(ByVal msg As String)
        outputBlock.Text &= msg 
    End Sub

End Class 

' This code example produces output similar to the following:
'
'WriterThread writing value: 1
'ReaderThread reading value: 1
'WriterThread writing value: 2
'ReaderThread reading value: 2
'WriterThread writing value: 3
'ReaderThread reading value: 3
'WriterThread writing value: 4
'ReaderThread reading value: 4
'WriterThread writing value: 5
'ReaderThread reading value: 5
'WriterThread writing value: 6
'ReaderThread reading value: 6
'WriterThread writing value: 7
'ReaderThread reading value: 7
'WriterThread writing value: 8
'ReaderThread reading value: 8
'WriterThread writing value: 9
'ReaderThread reading value: 9
'WriterThread writing value: 10
'ReaderThread reading value: 10
using System;
using System.Threading;
using System.Text;

class Example
{
    private const int numIterations = 10;

    // Create an AutoResetEvent that is initially not signaled.
    private static AutoResetEvent myResetEvent = new AutoResetEvent(false);

    private static int number;
    private static bool running = true;
    private static StringBuilder output = new StringBuilder();
    private static System.Windows.Controls.TextBlock outputBlock;

    public static void Demo(System.Windows.Controls.TextBlock outputBlock)
    {
        Example.outputBlock = outputBlock;

        // Create and start the reader thread.
        Thread myReaderThread = new Thread(MyReadThreadProc);
        myReaderThread.Name = "ReaderThread";
        myReaderThread.Start();

        // Create and start the writer thread.
        Thread myWriterThread = new Thread(MyWriteThreadProc);
        myWriterThread.Name = "WriterThread";
        myWriterThread.Start();
    }

    public static void MyReadThreadProc()
    {
        while (running)
        {
            // The value will not be read until the writer has written
            // at least once since the last read.
            myResetEvent.WaitOne();

            lock (output)
            {
                output.AppendLine(String.Format("{0} reading value: {1}", 
                    Thread.CurrentThread.Name, number));
            }
        }
    }

    public static void MyWriteThreadProc()
    {
        for(int i = 1; i <= numIterations; i++)
        {
            lock (output)
            {
                output.AppendLine(String.Format("{0} writing value: {1}", 
                    Thread.CurrentThread.Name, i));
            }

            number = i;

            // Signal that a value has been written.
            myResetEvent.Set();

            // Give the Reader thread an opportunity to act.
            Thread.Sleep(1);
        }

        // Terminate the reader thread.
        running = false;
        myResetEvent.Set();

        lock (output)
        {
            // Append the output from the example to the TextBlock control.
            // In order to update the TextBlock object, which is on the UI thread,
            // you must make a cross-thread call by using the Dispatcher object 
            // that is associated with the TextBlock.
            outputBlock.Dispatcher.BeginInvoke(delegate () {
                outputBlock.Text += output.ToString(); });
        }
    }
}

/* This code example produces output similar to the following:

WriterThread writing value: 1
ReaderThread reading value: 1
WriterThread writing value: 2
ReaderThread reading value: 2
WriterThread writing value: 3
ReaderThread reading value: 3
WriterThread writing value: 4
ReaderThread reading value: 4
WriterThread writing value: 5
ReaderThread reading value: 5
WriterThread writing value: 6
ReaderThread reading value: 6
WriterThread writing value: 7
ReaderThread reading value: 7
WriterThread writing value: 8
ReaderThread reading value: 8
WriterThread writing value: 9
ReaderThread reading value: 9
WriterThread writing value: 10
ReaderThread reading value: 10
 */

Example 2

The following example demonstrates how to use AutoResetEvent with ManualResetEvent to synchronize the activities of multiple threads, including the UI thread.

NoteNote:

For a more detailed description of this example, see the comments in the code or the full introduction to the example that is provided for the EventWaitHandle class.

An AutoResetEvent is used to synchronize the user interface thread with the DemoThread method that runs the example. The thread that executes the DemoThread method blocks on an AutoResetEvent between steps. In the MouseUp method, which handles the MouseLeftButtonUp event, the Set method is used to signal the AutoResetEvent, so that clicking the mouse runs the next step. AutoResetEvent is a good choice because it automatically resets to the non-signaled state.

AutoResetEvent is also used in the ThreadProc and ThreadProcARE thread procedures. In these cases, the AutoResetEvent is passed to the thread procedure as a parameter. The main thread, DemoThread, waits for the AutoResetEvent until ThreadProc or ThreadProcARE signals it to proceed by calling Set. This ensures that the threads in the example are coordinated, particularly with respect to the order in which they append messages to the TextBlock control that displays the output from the example.

Imports System.Threading

' The following Imports are not required for ManualResetEvent or
' AutoResetEvent; they merely simplify the code.
Imports System.Windows.Controls
Imports System.Windows.Input

Public Class Example

   ' mre is used to block and release threads manually.
   Private Shared mre As New ManualResetEvent(False)

   ' The DemoThread method waits on this AutoResetEvent before each step of the
   ' demo. The MouseLeftButtonUp event handler calls Set to allow each step to
   ' run.
   Private Shared areSyncDemoThread As New AutoResetEvent(False)

   ' All output is displayed here.
   Private Shared outputBlock As TextBlock

   ' This array of AutoResetEvent objects is used to ensure that all the threads
   ' created for the first step of the demo are waiting on the ManualResetEvent
   ' before the step is executed, and to ensure that all the threads are complete
   ' before going on to the next step.
   Private Shared autoResets() As AutoResetEvent = { New AutoResetEvent(False), _
                          New AutoResetEvent(False), New AutoResetEvent(False) }


   ' The Shared Demo method starts the thread that controls the demo and hooks 
   ' up the handler for the MouseLeftButtonUp event.
   Public Shared Sub Demo(ByVal outputBlock As TextBlock)

      Example.outputBlock = outputBlock
      outputBlock.Text &= "Click here to begin the demo." & vbLf & vbLf

      Dim t As New Thread(AddressOf DemoThread)
      t.Start()

      AddHandler outputBlock.MouseLeftButtonUp, AddressOf MouseUp

   End Sub


   ' Each time the TextBlock is clicked, the mouse event handler calls Set() on 
   ' the AutoResetEvent, to signal DemoThread to execute the next step of the 
   ' demo. Optionally, it clears the TextBlock.
   '
   Private Shared clear As Boolean = False
   Private Shared Sub MouseUp(ByVal sender As Object, ByVal e As MouseButtonEventArgs)

      ' If the clear flag has been set, clear the contents of the TextBlock.
      If clear Then
         outputBlock.Text = ""
         clear = False
      End If
      'outputBlock.Text &= "Click." & vbLf

      ' Signal the next step of the demo to proceed.
      areSyncDemoThread.Set()

   End Sub


   ' Before each step of the demo, DemoThread waits on areSyncDemoThread. When
   ' the MouseLeftButtonUp event handler signals areSyncDemoThread, DemoThread
   ' executes the step. Because areSyncDemoThread is an AutoResetEvent, it 
   ' immediately resets after DemoThread is released.
   Private Shared Sub DemoThread()

      ' Wait for a mouse click.
      areSyncDemoThread.WaitOne()


      ' Step 1: Start 3 named threads that block on a ManualResetEvent.

      For i As Integer = 0 To 2
         Dim t As New Thread(AddressOf ThreadProc)
         t.Name = "Thread_" & i
         t.Start(autoResets(i))
      Next i

      ' Wait until all three threads have finished displaying their "start" 
      ' messages and called mre.WaitOne().
      WaitHandle.WaitAll(autoResets)

      outputBlock.Dispatcher.BeginInvoke(displayHelper, vbLf & _
         "3 threads are queued, waiting for the ManualResetEvent. Click to signal" & vbLf & _
         "the ManualResetEvent by calling its Set() method." & vbLf & vbLf)

      ' Wait for a mouse click.
      areSyncDemoThread.WaitOne()


      ' Step 2: Call mre.Set() to release the threads.

      mre.Set()

      ' Wait until all three threads have finished displaying their "end" 
      ' messages.
      WaitHandle.WaitAll(autoResets)

      outputBlock.Dispatcher.BeginInvoke(displayHelper, vbLf & _
         "All the threads were released, and the ManualResetEvent remains in the" & vbLf & _
         "signaled state. Click to start more threads." & vbLf & vbLf) 

      ' Wait for a mouse click.
      areSyncDemoThread.WaitOne()


      ' Step 3: Show that mre remains signaled by starting more threads. These
      '         threads will not block, so there is no reason to pass them an
      '         AutoResetEvent.

      Dim twoMoreThreads() As Thread = { New Thread(AddressOf ThreadProc), _
                                         New Thread(AddressOf ThreadProc) }
      For i As Integer = 0 To 1
         twoMoreThreads(i).Name = "Thread_" & (i + 3)
         twoMoreThreads(i).Start(Nothing)
      Next i

      ' Wait until the threads have displayed their messages and finished 
      ' executing.
      For Each t As Thread In twoMoreThreads
         t.Join()
      Next t

      outputBlock.Dispatcher.BeginInvoke(displayHelper, vbLf & _
         "As long as the ManualResetEvent remains in the signaled state, threads" & vbLf & _
         "that wait on it do not block. Click to reset the ManualResetEvent." & vbLf) 

      ' Wait for a mouse click.
      areSyncDemoThread.WaitOne()


      ' Step 4: Demonstrate that Reset puts the ManualResetEvent back into the
      '         unsignaled state.

      outputBlock.Dispatcher.BeginInvoke(displayHelper, vbLf & _
                                           "Calling mre.Reset()." & vbLf & vbLf)
      mre.Reset()

      ' Start a thread that waits on the ManualResetEvent.
      Dim t5 As New Thread(AddressOf ThreadProc)
      t5.Name = "Thread_5"
      Dim wait As New AutoResetEvent(False)
      t5.Start(wait)

      ' Wait until the thread has displayed its message and is waiting.
      wait.WaitOne()

      outputBlock.Dispatcher.BeginInvoke(displayHelper, vbLf & _
         "With the ManualResetEvent in the unsignaled state, threads once again block." & vbLf & _
         "Click to release the thread." & vbLf & vbLf)

      ' Signal the MouseUp event to clear the screen, and wait for a click.
      clear = True
      areSyncDemoThread.WaitOne()

      mre.Set()
      t5.Join()


      ' Step 5a: Signal an AutoResetEvent that does not have a thread waiting on
      '          it. Note that you can create an AutoResetEvent in the signaled
      '          state by using New AutoResetEvent(True).

      ' Put the AutoResetEvent into the signaled state.
      wait.Set()

      outputBlock.Dispatcher.BeginInvoke(displayHelper, vbLf & _
         "If an AutoResetEvent is signaled when there is no thread waiting on it, " & vbLf & _
         "the AutoResetEvent remains in the signaled state until a thread waits on" & vbLf & _
         "it. That thread is immediately released, and the AutoResetEvent returns" & vbLf & _
         "to the unsignaled state. Click here to demonstrate this." & vbLf & vbLf)

      ' Wait for a click.
      areSyncDemoThread.WaitOne()


      ' Step 5b: Create and release three threads that all wait on the signaled 
      '          AutoResetEvent. Each thread receives an array that contains two
      '          AutoResetEvent objects, one to signal when the thread is ready
      '          for release and one to wait on.

      ' Reset the ManualResetEvent that will synchronize the release of the three
      ' threads.
      mre.Reset()

      For i As Integer = 0 To 2
         Dim t As New Thread(AddressOf ThreadProcARE)
         t.Name = "Thread_" & (i + 6)
         t.Start(New AutoResetEvent() { autoResets(i), wait })
      Next i

      ' Wait until all three threads are queued, then release them all at once. 
      WaitHandle.WaitAll(autoResets)
      mre.Set()

      ' Wait until one thread has been released by the signaled AutoResetEvent and 
      ' has posted its message to the TextBlock.
      Dim winner As Integer = WaitHandle.WaitAny(autoResets)

      Dim name As String = "Thread_" & (winner + 6)
      outputBlock.Dispatcher.BeginInvoke(displayHelper, vbLf & name & _
         " was the first thread to wait on the signaled AutoResetEvent. As soon" & vbLf & _
         "as " & name & " was released, the AutoResetEvent was reset, blocking the other two" _
         & vbLf & "threads. Click to release the waiting threads." & vbLf & vbLf)

      ' Wait for a click.
      areSyncDemoThread.WaitOne()


      ' Step 6: Release threads and dispose of the Shared resources.

      outputBlock.Dispatcher.BeginInvoke(displayHelper, _
         "Set() is called twice on the AutoResetEvent, releasing one waiting thread" & vbLf & _ 
         "each time. In order to ensure that both threads are released, a suitable delay" & vbLf & _
         "must elapse between calls to Set(). This is accomplished by calling WaitAny()" & vbLf & _
         "on the autoResets array." & vbLf & vbLf)
      wait.Set()
      WaitHandle.WaitAny(autoResets)
      wait.Set()

      ' To ensure that both threads have ended before DemoThread ends, WaitAny()  
      ' is called to wait for the last thread to end. When DemoThread ends, the
      ' variable 'wait' goes out of scope and the AutoResetEvent it holds is reclaimed
      ' by garbage collection. If the thread is not released before this, it will not
      ' be released (and therefore will not run) and it will not be reclaimed by 
      ' collection until the application ends. You might think that the end of
      ' DemoThread and the end of the application are synonymous, but in fact the
      ' application is still running as long as the browser window remains active.
      ' The questions of whether it is important for the last thread to run before 
      ' the application ends, or whether it is a problem to temporarily leak the
      ' thread, will have different answers from application to application.
      WaitHandle.WaitAny(autoResets)

      ' Dispose of the shared (class-level) wait handles. This is important only
      ' if the program will go on running, and the wait handles will not be used.
      mre.Close()
      areSyncDemoThread.Close()
      For Each are As AutoResetEvent In autoResets
         are.Close()
      Next

      ' Unhook the mouse button event.
      outputBlock.Dispatcher.BeginInvoke(unhookHelper)

      outputBlock.Dispatcher.BeginInvoke(displayHelper, vbLf & _
         "To run the demo again, refresh the page." & vbLf)

   End Sub


   ' Thread Procedures:

   ' This thread procedure is executed by most of the named threads created in 
   ' this example.
   Private Shared Sub ThreadProc(ByVal state As Object)

      Dim are As AutoResetEvent = CType(state, AutoResetEvent)
      Dim name As String = Thread.CurrentThread.Name

      outputBlock.Dispatcher.BeginInvoke(displayHelper, _
                                name & " starts and calls mre.WaitOne()" & vbLf)

      ' Signal that the thread is about to wait.
      If are IsNot Nothing Then are.Set()

      ' Wait until the ManualResetEvent is signaled.
      mre.WaitOne()

      outputBlock.Dispatcher.BeginInvoke(displayHelper, name & " ends." & vbLf)

      ' Signal that the thread is about to exit.
      If are IsNot Nothing Then are.Set()
   End Sub


   ' This thread procedure is used by the last step, which shows the behavior
   ' of an AutoResetEvent that has been left in the signaled state.
   Private Shared Sub ThreadProcARE(ByVal state As Object)

      ' Get two AutoResetEvent objects, one to signal when this thread is ready
      ' for release, and one to wait on. The second AutoResetEvent may already
      ' be in the signaled state.
      Dim are() As AutoResetEvent = CType(state, AutoResetEvent())
      Dim name As String = Thread.CurrentThread.Name

      ' Signal that this thread is ready for release.
      are(0).Set()

      ' All threads are started at once, when mre is signaled.
      mre.WaitOne()

      outputBlock.Dispatcher.BeginInvoke(displayHelper, _
                         name & " waits on the AutoResetEvent" & vbLf)

      ' Wait on the previously signaled AutoResetEvent.
      are(1).WaitOne()

      outputBlock.Dispatcher.BeginInvoke(displayHelper, name & " ends." & vbLf)

      ' Signal that this thread is ready to end.
      are(0).Set()

   End Sub


   ' Helper methods:

   ' In order to update the TextBlock object, which is on the UI thread, you must
   ' make a cross-thread call by using the Dispatcher object that is associated 
   ' with the TextBlock. The DisplayOutput helper method and its delegate, 
   ' displayHelper, are used by the BeginInvoke method of the Dispatcher object
   ' to append text to the TextBlock. UnhookMouseUp and its delegate, unhookHelper,
   ' unhook the event handler for the MouseLeftButtonUp event.
   '
   Private Shared displayHelper As New Action(Of String)(AddressOf DisplayOutput)
   Private Shared Sub DisplayOutput(ByVal msg As String)
      outputBlock.Text &= msg 
   End Sub

   Private Shared unhookHelper As New Action(AddressOf UnhookMouseUp)
   Private Shared Sub UnhookMouseUp()
      RemoveHandler outputBlock.MouseLeftButtonUp, AddressOf MouseUp
   End Sub

End Class

' This example produces output similar to the following:
'
'Click here to begin the demo.
'
'Thread_0 starts and calls mre.WaitOne()
'Thread_1 starts and calls mre.WaitOne()
'Thread_2 starts and calls mre.WaitOne()
'
'3 threads are queued, waiting for the ManualResetEvent. Click to signal
'the ManualResetEvent by calling its Set() method.
'
'Thread_2 ends.
'Thread_1 ends.
'Thread_0 ends.
'
'All the threads were released, and the ManualResetEvent remains in the
'signaled state. Click to start more threads.
'
'Thread_3 starts and calls mre.WaitOne()
'Thread_3 ends.
'Thread_4 starts and calls mre.WaitOne()
'Thread_4 ends.
'
'As long as the ManualResetEvent remains in the signaled state, threads
'that wait on it do not block. Click to reset the ManualResetEvent.
'
'Calling mre.Reset()
'
'Thread_5 starts and calls mre.WaitOne()
'
'With the ManualResetEvent in the unsignaled state, threads once again block.
'Click to release the thread.
'
'Thread_5 ends.
'
'If an AutoResetEvent is signaled when there is no thread waiting on it, 
'the AutoResetEvent remains in the signaled state until a thread waits on
'it. That thread is immediately released, and the AutoResetEvent returns
'to the unsignaled state. Click here to demonstrate this.
'
'Thread_7 waits on the AutoResetEvent.
'Thread_7 ends.
'Thread_8 waits on the AutoResetEvent.
'Thread_6 waits on the AutoResetEvent.
'
'Thread_7 was the first thread to wait on the signaled AutoResetEvent. As soon
'as Thread_7 was released, the AutoResetEvent was reset, blocking the other
'two threads. Click to release the waiting threads.
'
'Set() is called twice on the AutoResetEvent, releasing one waiting thread 
'each time. In order to ensure that both threads are released, a suitable delay
'must elapse between calls to Set(). This is accomplished by calling WaitAny()
'on the autoResets array.
'
'Thread_8 ends.
'Thread_6 ends.
'
'To run the demo again, refresh the page.
using System;
using System.Threading;

// The following Imports are not required for ManualResetEvent or
// AutoResetEvent; they merely simplify the code.
using System.Windows.Controls;
using System.Windows.Input;

public class Example
{
   // mre is used to block and release threads manually.
   private static ManualResetEvent mre = new ManualResetEvent(false);

   // The DemoThread method waits on this AutoResetEvent before each step of the
   // demo. The MouseLeftButtonUp event handler calls Set to allow each step to
   // run.
   private static AutoResetEvent areSyncDemoThread = new AutoResetEvent(false);

   // All output is displayed here.
   private static TextBlock outputBlock;

   // This array of AutoResetEvent objects is used to ensure that all the threads
   // created for the first step of the demo are waiting on the ManualResetEvent
   // before the step is executed, and to ensure that all the threads are complete
   // before going on to the next step.
   private static AutoResetEvent[] autoResets = { new AutoResetEvent(false), 
                       new AutoResetEvent(false), new AutoResetEvent(false)};


   // The static Demo method starts the thread that controls the demo and hooks 
   // up the handler for the MouseLeftButtonUp event.
   public static void Demo(TextBlock outputBlock)
   {
      Example.outputBlock = outputBlock;
      outputBlock.Text += "Click here to begin the demo.\n\n";

      Thread t = new Thread(DemoThread);
      t.Start();

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


   // Each time the TextBlock is clicked, the mouse event handler calls Set() on 
   // the AutoResetEvent, to signal DemoThread to execute the next step of the 
   // demo. Optionally, it clears the TextBlock.
   //
   private static bool clear = false;
   private static void MouseUp(object sender, MouseButtonEventArgs e)
   {
      // If the clear flag has been set, clear the contents of the TextBlock.
      if (clear)
      {
         outputBlock.Text = "";
         clear = false;
      }
      //outputBlock.Text += "Click.\n"

      // Signal the next step of the demo to proceed.
      areSyncDemoThread.Set();
   }


   // Before each step of the demo, DemoThread waits on areSyncDemoThread. When
   // the MouseLeftButtonUp event handler signals areSyncDemoThread, DemoThread
   // executes the step. Because areSyncDemoThread is an AutoResetEvent, it 
   // immediately resets after DemoThread is released.
   private static void DemoThread()
   {
      // Wait for a mouse click.
      areSyncDemoThread.WaitOne();


      // Step 1: Start 3 named threads that block on a ManualResetEvent.

      for(int i = 0; i < 3; i++)
      {
         Thread t = new Thread(ThreadProc);
         t.Name = "Thread_" + i;
         t.Start(autoResets[i]);
      }

      // Wait until all three threads have finished displaying their "start" 
      // messages and called mre.WaitOne().
      WaitHandle.WaitAll(autoResets);

      outputBlock.Dispatcher.BeginInvoke(displayHelper, 
         "\n3 threads are queued, waiting for the ManualResetEvent. Click to signal\n" + 
         "the ManualResetEvent by calling its Set() method.\n\n");

      // Wait for a mouse click.
      areSyncDemoThread.WaitOne();


      // Step 2: Call mre.Set() to release the threads.

      mre.Set();

      // Wait until all three threads have finished displaying their "end" 
      // messages.
      WaitHandle.WaitAll(autoResets);

      outputBlock.Dispatcher.BeginInvoke(displayHelper, 
         "\nAll the threads were released, and the ManualResetEvent remains in the\n" + 
         "signaled state. Click to start more threads.\n\n");

      // Wait for a mouse click.
      areSyncDemoThread.WaitOne();


      // Step 3: Show that mre remains signaled by starting more threads. These
      //         threads will not block, so there is no reason to pass them an
      //         AutoResetEvent.

      Thread[] twoMoreThreads = {new Thread(ThreadProc), new Thread(ThreadProc)};
      for(int i = 0; i < 2; i++)
      {
         twoMoreThreads[i].Name = "Thread_" + (i + 3);
         twoMoreThreads[i].Start(null);
      }

      // Wait until the threads have displayed their messages and finished 
      // executing.
      foreach (Thread t in twoMoreThreads)
      {
         t.Join();
      }

      outputBlock.Dispatcher.BeginInvoke(displayHelper, 
         "\nAs long as the ManualResetEvent remains in the signaled state, threads\n" + 
         "that wait on it do not block. Click to reset the ManualResetEvent.\n");

      // Wait for a mouse click.
      areSyncDemoThread.WaitOne();


      // Step 4: Demonstrate that Reset puts the ManualResetEvent back into the
      //         unsignaled state.

      outputBlock.Dispatcher.BeginInvoke(displayHelper, "\nCalling mre.Reset().\n\n");
      mre.Reset();

      // Start a thread that waits on the ManualResetEvent.
      Thread t5 = new Thread(ThreadProc);
      t5.Name = "Thread_5";
      AutoResetEvent wait = new AutoResetEvent(false);
      t5.Start(wait);

      // Wait until the thread has displayed its message and is waiting.
      wait.WaitOne();

      outputBlock.Dispatcher.BeginInvoke(displayHelper, 
         "\nWith the ManualResetEvent in the unsignaled state, threads once again block.\n" + 
         "Click to release the thread.\n\n");

      // Signal the MouseUp event to clear the screen, and wait for a click.
      clear = true;
      areSyncDemoThread.WaitOne();

      // Release the waiting thread, and block until it ends.
      mre.Set();
      t5.Join();


      // Step 5a: Signal an AutoResetEvent that does not have a thread waiting on
      //          it. Note that you can create an AutoResetEvent in the signaled
      //          state by using New AutoResetEvent(True).

      // Put the AutoResetEvent into the signaled state.
      wait.Set();

      outputBlock.Dispatcher.BeginInvoke(displayHelper, 
         "\nIf an AutoResetEvent is signaled when there is no thread waiting on it, \n" + 
         "the AutoResetEvent remains in the signaled state until a thread waits on\n" + 
         "it. That thread is immediately released, and the AutoResetEvent returns\n" + 
         "to the unsignaled state. Click here to demonstrate this.\n\n");

      // Wait for a click.
      areSyncDemoThread.WaitOne();


      // Step 5b: Create and release three threads that all wait on the signaled 
      //          AutoResetEvent. Each thread receives an array that contains two
      //          AutoResetEvent objects, one to signal when the thread is ready
      //          for release and one to wait on.

      // Reset the ManualResetEvent that will synchronize the release of the three
      // threads.
      mre.Reset();

      for(int i=0; i<=2; i++)
      {
         Thread t = new Thread(ThreadProcARE);
         t.Name = "Thread_"+ (i + 6);
         t.Start(new AutoResetEvent[]{ autoResets[i], wait });
      }

      // Wait until all three threads are queued, then release them all at once. 
      WaitHandle.WaitAll(autoResets);
      mre.Set();

      // Wait until one thread has been released by the signaled AutoResetEvent and 
      // has posted its message to the TextBlock.
      int winner = WaitHandle.WaitAny(autoResets);

      string name = "Thread_" + (winner + 6);
      outputBlock.Dispatcher.BeginInvoke(displayHelper, "\n" + name +
         " was the first thread to wait on the signaled AutoResetEvent. As soon\n" +
         "as " + name + " was released, the AutoResetEvent was reset, blocking the other two\n" +
         "threads. Click to release the waiting threads.\n\n");

      // Wait for a click.
      areSyncDemoThread.WaitOne();


      // Step 6: Release threads and dispose of the Shared resources.

      outputBlock.Dispatcher.BeginInvoke(displayHelper, 
         "Set() is called twice on the AutoResetEvent, releasing one waiting thread\n" + 
         "each time. In order to ensure that both threads are released, a suitable delay\n" +
         "must elapse between calls to Set(). This is accomplished by calling WaitAny()\n" +
         "on the autoResets array.\n\n");
      wait.Set();
      WaitHandle.WaitAny(autoResets);
      wait.Set();

      // To ensure that both threads have ended before DemoThread ends, WaitAny()  
      // is called to wait for the last thread to end. When DemoThread ends, the
      // variable 'wait' goes out of scope and the AutoResetEvent it holds is reclaimed
      // by garbage collection. If the thread is not released before this, it will not
      // be released (and therefore will not run) and it will not be reclaimed by 
      // collection until the application ends. You might think that the end of
      // DemoThread and the end of the application are synonymous, but in fact the
      // application is still running as long as the browser window remains active.
      // The questions of whether it is important for the last thread to run before 
      // the application ends, or whether it is a problem to temporarily leak the
      // thread, will have different answers from application to application.
      WaitHandle.WaitAny(autoResets);

      // Dispose of the static (class-level) wait handles. This is important only
      // if the program will go on running, and the wait handles will not be used.
      mre.Close();
      areSyncDemoThread.Close();
      foreach (AutoResetEvent are in autoResets)
      {
         are.Close();
      }

      // Unhook the mouse button event.
      outputBlock.Dispatcher.BeginInvoke(delegate () {
         outputBlock.MouseLeftButtonUp -= new MouseButtonEventHandler(MouseUp); });

      outputBlock.Dispatcher.BeginInvoke(displayHelper, 
         "\nTo run the demo again, refresh the page.\n");
   }


   // Thread Procedures:

   // This thread procedure is executed by most of the named threads created in 
   // this example.
   private static void ThreadProc(object state)
   {
      AutoResetEvent are = (AutoResetEvent) state;
      string name = Thread.CurrentThread.Name;

      outputBlock.Dispatcher.BeginInvoke(displayHelper, 
                                   name + " starts and calls mre.WaitOne()\n");

      // Signal that the thread is about to wait.
      if (are != null) { are.Set(); }

      // Wait until the ManualResetEvent is signaled.
      mre.WaitOne();

      outputBlock.Dispatcher.BeginInvoke(displayHelper, name + " ends.\n");

      // Signal that the thread is about to exit.
      if (are != null) { are.Set(); }
   }


   // This thread procedure is used by the last step, which shows the behavior
   // of an AutoResetEvent that has been left in the signaled state.
   private static void ThreadProcARE(object state)
   {
      // Get two AutoResetEvent objects, one to signal when this thread is ready
      // for release, and one to wait on. The second AutoResetEvent is already
      // in the signaled state.
      AutoResetEvent[] are = (AutoResetEvent[]) state;
      string name = Thread.CurrentThread.Name;

      // Signal that this thread is ready for release.
      are[0].Set();

      // All threads are started at once, when mre is signaled.
      mre.WaitOne();

      outputBlock.Dispatcher.BeginInvoke(displayHelper, 
                                    name + " waits on the AutoResetEvent.\n");

      // Wait on the previously signaled AutoResetEvent.
      are[1].WaitOne();

      outputBlock.Dispatcher.BeginInvoke(displayHelper, name + " ends.\n");

      // Signal that this thread is ready to end.
      are[0].Set();
   }


   // Helper methods:

   // In order to update the TextBlock object, which is on the UI thread, you must
   // make a cross-thread call by using the Dispatcher object that is associated 
   // with the TextBlock. The DisplayOutput helper method and its delegate, 
   // displayHelper, are used by the BeginInvoke method of the Dispatcher object
   // to append text to the TextBlock.
   //
   private static Action<string> displayHelper = new Action<string>(DisplayOutput);
   private static void DisplayOutput(string msg)
   {
      outputBlock.Text += msg;
   }
}

/* This example produces output similar to the following:

Click here to begin the demo.

Thread_0 starts and calls mre.WaitOne()
Thread_1 starts and calls mre.WaitOne()
Thread_2 starts and calls mre.WaitOne()

3 threads are queued, waiting for the ManualResetEvent. Click to signal
the ManualResetEvent by calling its Set() method.

Thread_2 ends.
Thread_1 ends.
Thread_0 ends.

All the threads were released, and the ManualResetEvent remains in the
signaled state. Click to start more threads.

Thread_3 starts and calls mre.WaitOne()
Thread_3 ends.
Thread_4 starts and calls mre.WaitOne()
Thread_4 ends.

As long as the ManualResetEvent remains in the signaled state, threads
that wait on it do not block. Click to reset the ManualResetEvent.

Calling mre.Reset()

Thread_5 starts and calls mre.WaitOne()

With the ManualResetEvent in the unsignaled state, threads once again block.
Click to release the thread.

Thread_5 ends.

If an AutoResetEvent is signaled when there is no thread waiting on it, 
the AutoResetEvent remains in the signaled state until a thread waits on
it. That thread is immediately released, and the AutoResetEvent returns
to the unsignaled state. Click here to demonstrate this.

Thread_7 waits on the AutoResetEvent.
Thread_7 ends.
Thread_8 waits on the AutoResetEvent.
Thread_6 waits on the AutoResetEvent.

Thread_7 was the first thread to wait on the signaled AutoResetEvent. As soon
as Thread_7 was released, the AutoResetEvent was reset, blocking the other
two threads. Click to release the waiting threads.

Set() is called twice on the AutoResetEvent, releasing one waiting thread 
each time. In order to ensure that both threads are released, a suitable delay
must elapse between calls to Set(). This is accomplished by calling WaitAny()
on the autoResets array.

Thread_8 ends.
Thread_6 ends.

To run the demo again, 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.

Thread Safety

This class is thread safe.