. NET Synchronous and asynchronous EventWaitHandle

Source: Internet
Author: User
Tags semaphore
In the previous article we have mentioned that the mutex and the protagonist of this article directly or indirectly http://www.php.cn/code/6064.html "target=" _blank "> Inherit from WaitHandle:

    • The mutex class, which we have already talked about in the previous article.

    • EventWaitHandle class and its derived classes AutoResetEvent and ManualResetEvent, this is the protagonist of this article.

    • Semaphore class, that is, the semaphore, we will talk about next (suddenly feel that there is no need to introduce).

WaitHandle provides several methods for synchronizing. A WaitOne () has been mentioned in the previous blog about mutexes, which is an example method. In addition, WaitHandle has 3 additional static methods for synchronization:

    • SignalAndWait (WaitHandle, WaitHandle): Sends a signal to the first WaitHandle and waits for the second one in atomic operation. That is, wake up the thread/process blocking on the first WaitHandle, and then wait for the second WaitHandle yourself, and the two actions are atomic. As with WaitOne (), this method has another two overloaded methods, using Int32 or TimeSpan to define the wait time-out period, and whether to exit from the context's synchronization domain.

    • WaitAll (waithandle[]): This is used to wait for all members in the WaitHandle array. This approach is a good choice if you need to wait for everyone in front of you to finish before you can continue. There are still two overloaded methods to control the wait timeout, see for yourself.

    • WaitAny (waithandle[]): Unlike WaitAll (), WaitAny is returned when a member of the array receives a signal. If you have a job, you can start by waiting for the quickest finish, then WaitAny () is all you need. It also has two overloads to control the wait timeout.

Thread affinity

    • A mutex, like monitor, has thread affinity. As we have mentioned before, only the thread that obtains the object lock through Monitor.Enter ()/tryenter () can invoke Pulse ()/wait ()/exit (); Similarly, only the thread that obtains the ownership of the mutex can execute ReleaseMutex ( ) method, or an exception is thrown. This is known as thread affinity.

    • Conversely, eventwaithandle and its derived classes AutoResetEvent and ManualResetEvent are thread-independent. Any thread can send a signal to EventWaitHandle to wake up the thread that is blocking it.

    • The next semaphore to mention is thread-independent.

Event notification

EventWaitHandle, AutoResetEvent, and ManualResetEvent have an "event" in their name, but this has nothing to do with the event mechanism of. NET itself, which does not involve any delegation or event handlers. Compared to the monitor and mutex we met before we needed threads to compete for "locks", we could interpret them as "events" that require threads to wait. Threads block themselves by waiting for the "occurrence" of these events. Once the "event" is complete, the blocked thread can continue to work after the signal is received.

In order to match the 3 static methods on the WaitHandle singnalandwait ()/wailany ()/waitall (), EventWaitHandle provides its own unique way of getting the "Event" to complete and restart:

        BOOL: Set (): English msdn:sets The state of the "event to signaled", allowing one or more waiting threads to proceed; MSDN: Set event status to terminating Allow one or more waiting threads to continue. At first glance, "signaled" and "termination" do not seem to correspond to the idea of the two statements in fact, there is no contradiction. If the event is in progress, of course there is no "stop", then the other threads will have to wait, once the event is complete, then the event is "terminated", so we send a signal wake-up waiting for the thread, so "signal sent" state is also reasonable. Two small details:

        1. Both Chinese and English, it is mentioned that this method allows "one" or "multiple" waiting threads to "continue/proceed" (note that it is not "Wake-up"). So this method is similar to Monitor.pulse () and Monitor.pulseall () in the "Wake" action. As for when Pulse () is similar to PulseAll (), look down.

        2. This method has the return value of type bool: TRUE if the operation succeeds; otherwise, false. But MSDN doesn't tell us when execution will fail, you only have to ask for a Microsoft MVP.

      • Bool:reset (): Sets the state of the event to nonsignaled, causing threads to block. Set event status to non-terminating Causes the thread to block. Again, we need to understand that "nonsignaled" and "non-termination" are the same thing. Also, there is still an unreasonable return value. Reset () is equivalent to having the event restart in "in progress", then all WaitOne ()/waitall ()/waitany ()/signalandwait () The thread of this event will be blocked out of the door again.

constructor function

Let's take a look at the simplest of the many EventWaitHandle constructors:

    • EventWaitHandle (Boolean initialstate, EventResetMode mode): Initializes a new instance of the EventWaitHandle class and specifies whether the wait handle is initially in a signaled state. and whether it is automatically reset or manual reset. Most of the time we will use false in the first argument so that the new instance defaults to the "non-terminating" state. The second parameter, EventResetMode, is an enumeration with a total of two values:

      1. eventresetmode.autoreset: When set () is called the current eventwaithandle goes to the terminating state, if the thread is blocked on the current eventwaithandle, then release a After the thread eventwaithandle is automatically reset (equivalent to automatically calling reset ()) into the non-terminating state again, the remaining blocked threads (if any) will continue to block. If there is no thread blocking after calling set (), then EventWaitHandle will remain "signaled" until a thread tries to wait for the event, and the thread will not be blocked, and then EventWaitHandle will automatically reset and block all threads after that.

      2. eventresetmode.manualreset: When terminating, EventWaitHandle frees all waiting threads and remains signaled until reset () is called before a manual reset.

Well, now we can clearly know when set () is similar to Monitor.pulse ()/pulseall ():

    • When EventWaitHandle is working in Autoreset mode, Set () is similar to Monitor.pulse () in terms of wake-up function. At this point, Set () can only wake up one of the many (if there are multiple) blocked threads. But there are still some differences:

      1. Set () does not only "wake" but "release", allowing the thread to continue to work (proceed), whereas the Pulse () wake thread simply re-enters the running state and participates in the object lock contention, and no one can guarantee that it will get the object lock.

      2. The called State of Pulse () is not maintained. Therefore, if you call pulse () when there is no waiting thread, the next call to Monitor.Wait () will still be blocked, just as pulse () has not been called. That is, Monitor.pulse () works only at the time of invocation, and does not function as set () until the next waitxxx ().

    • When a set () method that works in Manualreset mode is called, its wake-up effect is similar to Monitor.pulseall (), and all blocked threads receive a signal to wake up. The difference between the two is exactly the same as above.

Take a look at the other constructors of EventWaitHandle:

    • EventWaitHandle (Boolean initialstate, EventResetMode mode, String name): The first two parameters we have seen, the third parameter name is used to specify the name of the synchronization event within the system scope. Yes, as we mentioned in the mutex article, because the parent class WaitHandle is capable of cross-process domains, like a mutex, we can create a global eventwaithandle that is then used for inter-process notifications. Note that the name is still case sensitive and there is still a problem with the naming prefix, which you can refer to here. When name is null or an empty string, this is equivalent to creating a partial unnamed eventwaithandle. Still, it is possible that a eventwaithandle with the same name already exists in the system and simply returns an instance representing the EventWaitHandle with the same name. So finally, again, if you need to know whether the EventWaitHandle was created by you first, you need to use one of the following two constructors.

    • EventWaitHandle (Boolean initialstate, EventResetMode mode, String name, out Boolean creatednew) : Creatednew is used to indicate whether the successful creation of EVENTWAITHANDLE,TRUE indicates success, and False indicates that an event with the same name already exists.

    • EventWaitHandle (Boolean initialstate, EventResetMode mode, String name, out Boolean creatednew, eventwaithandlesecurity ): For security issues, look directly at the example on this constructor. Global Mutexeventwaithandle security issues should be more noticeable relative to mutexes, because it is possible that a hacker program can signal or organize your thread with the same event name, which can seriously compromise your business logic.

MSDN Demo


Using system;using System.threading;public class example{//The eventwaithandle used to demonstrate the difference    Between AutoReset and Manualreset synchronization events.    private static EventWaitHandle EWH; A counter to make sure all threads is started and//blocked before any is released.    A Long is used-show//The use of the 64-bit interlocked methods.    private static Long threadcount = 0;    An AutoReset event This allows the main thread to block//until a exiting thread has decremented the count.    private static EventWaitHandle Clearcount = new EventWaitHandle (false, Eventresetmode.autoreset);        [Mtathread] public static void Main () {//Create an AutoReset eventwaithandle.        EWH = new EventWaitHandle (false, Eventresetmode.autoreset); Create and start five numbered threads. Use the//Parameterizedthreadstart delegate, so the thread//number can passed asAn argument to the Start/method. for (int i = 0; I <= 4; i++) {Thread t = new Thread (New Parameterizedthreadstart (Thr            Eadproc));        T.start (i);        }//Wait until all the threads has started and blocked. When multiple threads use a 64-bit value in a 32-bit//system, you must access the value through the//        Interlocked class to guarantee thread safety.        while (Interlocked.read (ref ThreadCount) < 5) {Thread.Sleep (500);        }//Release one thread each time the user presses ENTER,//until all threads has been released.  while (Interlocked.read (ref ThreadCount) > 0) {Console.WriteLine ("Press ENTER to release a            Waiting thread. ");            Console.ReadLine ();       SignalAndWait signals the EventWaitHandle, which//releases exactly one thread before resetting,      Because it is created with AutoReset mode.            SignalAndWait then blocks on Clearcount, to/from the signaled thread to decrement the count            Before looping again.        Waithandle.signalandwait (EWH, Clearcount);        } Console.WriteLine ();        Create a manualreset eventwaithandle.        EWH = new EventWaitHandle (false, Eventresetmode.manualreset);        Create and start five more numbered threads. for (int i=0; i<=4; i++) {Thread t = new Thread (New Parameterizedthreadstar            T (ThreadProc));        T.start (i);        }//Wait until all the threads has started and blocked.        while (Interlocked.read (ref ThreadCount) < 5) {Thread.Sleep (500);        }//Because the EventWaitHandle is created with//Manualreset mode, signaling it releases all the Waiting threAds.        Console.WriteLine ("Press ENTER to release the waiting threads.");        Console.ReadLine (); Ewh.    Set ();        } public static void ThreadProc (object data) {int index = (int) data;        Console.WriteLine ("Thread {0} blocks.", data);        Increment the count of blocked threads.        Interlocked.Increment (ref threadcount);        Wait on the EventWaitHandle. Ewh.        WaitOne ();        Console.WriteLine ("Thread {0} exits.", data);        Decrement the count of blocked threads.        Interlocked.decrement (ref threadcount); After signaling EWH, the main thread blocks on//Clearcount until the signaled thread have//Decremente D The Count.        Signal it now.    Clearcount.set (); }}
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.