开发者

What is the basic concept behind WaitHandle?

What is the basic concept behind WaitHandle in C# .net threading? Whats is its use? When to use it? What is the use of WaitAll and WaitAny methods insid开发者_如何学运维e it?


Whenever you would want to control the execution of multiple threads in your app. Though this does not only mean that only one thread increments the counter; but let the threads start/stop or pause upon an event.

See WaitHandles - Auto/ManualResetEvent and Mutex

--EDIT--

WaitHandles are the mechanism that you "use" to control the threads' execution. Its not about handles not being accessible within a thread; its about using them within the thread.

This may be a fat example, but please bear with me; think about, a lady gives five different toned whistles to five girls, and tells them to blow the whistle whenever something would happen; the process is for each girl to blow a whistle, and the lady would know who blew the whistle.

Now, its not about sharing-the-whistles with each other, its about, probably for the lady, to use them to "control" the execution or the process how girls would blow the whistle.

Therefore, technically the process would be to:

  1. Create a wait event(ManualResetEvent object)
  2. Register the events, WaitHandle.WaitAny(events);
  3. After you are done performing operation in your thread, the .Set(), which would tell the WaitHandle that 'I am done!'.

For instance, consider the example from the link provided. I have added the steps for you to understand the logic. These aren't the hardcoded steps, but just so you may understand.

class Test
{
    static void Main()
    {
    //STEP 1: Create a wait handle
        ManualResetEvent[] events = new ManualResetEvent[10];//Create a wait handle
        for (int i=0; i < events.Length; i++)
        {
            events[i] = new ManualResetEvent(false);
            Runner r = new Runner(events[i], i); 
            new Thread(new ThreadStart(r.Run)).Start();
        }

    //STEP 2: Register for the events to wait for
        int index = WaitHandle.WaitAny(events); //wait here for any event and print following line.

        Console.WriteLine ("***** The winner is {0} *****", 
                           index);

        WaitHandle.WaitAll(events); //Wait for all of the threads to finish, that is, to call their cooresponding `.Set()` method.

        Console.WriteLine ("All finished!");
    }
}


class Runner
{
    static readonly object rngLock = new object();
    static Random rng = new Random();

    ManualResetEvent ev;
    int id;

    internal Runner (ManualResetEvent ev, int id)
    {
        this.ev = ev;//Wait handle associated to each object, thread in this case.
        this.id = id;
    }

    internal void Run()
    {
    //STEP 3: Do some work
        for (int i=0; i < 10; i++)
        {
            int sleepTime;
            // Not sure about the thread safety of Random...
            lock (rngLock)
            {
                sleepTime = rng.Next(2000);
            }
            Thread.Sleep(sleepTime);
            Console.WriteLine ("Runner {0} at stage {1}",
                               id, i);
        }

    //STEP 4: Im done!
        ev.Set();
    }
}


WaitHandle is an abstract base class for the two commonly used event handles: AutoResetEvent and ManualResetEvent.

Both of these classes allow one thread to "signal" one or more other threads. They're used to synchronize (or serialize activity) between threads. This is accomplished using the Set and WaitOne (or WaitAll) methods. For example:

Thread 1:

// do setup work

myWaitHandle.Set();

Thread 2:

// do setup work

myWaitHandle.WaitOne();

// this code will not continue until after the call to `Set` 
// in thread 1 completes.

This is a very rudimentary example, and there are loads of them available on the web. The basic idea is that WaitOne is used to wait for a signal from another thread that indicates that something has happened. In the case of AsyncWaitHandle (which is returned from invoking a delegate asynchronously), WaitOne allows you to cause the current thread to wait until the async operation has completed.

When an AutoResetEvent or ManualResetEvent are not set, calls to WaitOne will block the calling thread until Set is called. These two classes differ only in that AutoResetEvent "unsets" the event once a successful call to WaitOne completes, making subsequent calls block again until Set is called. ManualResetEvent must be "unset" explicitly by calling Reset.

WaitAll and WaitAny are static methods on the WaitHandle class that allow you to specify an array of WaitHandles to wait on. WaitAll will block until all of the supplied handles are Set, whereas WaitAny will only block until one of them gets Set.


It is an abstract class, you don't use it directly. Concrete derived classes are ManualResetEvent, AutoResetEvent, Mutex and Semaphore. Important classes in your toolbox to implement thread synchronization. They inherit the WaitOne, WaitAll and WaitAny methods, you use them to detect that one or more threads signaled the wait condition.

Typical usage scenario for Manual/AutoResetEvent is to tell a thread to exit or to let a thread signal that it has progressed to an important sequence point. Semaphore helps you to limit the number of threads that perform an action. Or to implement threading synchronization that should not have affinity to a particular thread. Mutex is there to assign ownership to a section of code to one thread, the lock statement is often applicable there as well.

Books have been written about it. Joe Duffy's Concurrent Programming in Windows is the latest and greatest. Strongly recommended if you contemplate writing threaded code.


Imagine you have an array with 1000 items in it. You need to do some processing on every one of those items. This work will take some time, but is not I/O bound.

For example, maybe you need to use each item to make a low-bandwidth web request. You have plenty of throughput to request many items at the same time, and the latency in each web request means doing one at a time could take longer than you want.

Enter the world of parallel programming. Today there are a number of ways you can handle this task, and WaitHandle is a fundamental part of it. Even if you don't use a WaitHandle directly, whatever option you choose is likely relying on a WaitHandle such as WaitAll or WaitAny behind the scenes.

Continuing the example, let's say you have a typical four-core CPU. In this situation, it doesn't make a lot of sense to have more than 4 threads going at once.* So 4 threads, but 1000 items; what do you do?

One option uses WaitAny. You kick off 4 threads, and every time the WaitAny method returns you kick off another, until all 1000 items are queued. Note this is a poor example for WaitAny, because we know how many items there in total and can access any of the items at the same rate. WaitAny is best when you only have sequential access. There are other, similar situations where WaitAny can make a lot of sense.

Another option uses WaitAll. Instead of queuing one item at a time, you set up one thread for each of the four cores assign it a different 250 item segment of the array. With this option, you can use WaitAll to wait for all the processing to finish.


* Actually, it does. There's usually a certain amount of I/O time where the CPU would be idle, such that you can do better by having more than one thread going per core. But that's a story for another time.


There are some very long answers here. For anyone looking for the short answer:

Wait handle are a mechanism for making one thread wait until another thread reaches a certain point.

You can also have several threads waiting and/or several threads that are being waited for, hence the WaitOne, WaitAll and WaitAny methods. There are also several options for semantics available by choosing one of these classes: Mutex, Semaphore, ManualResetEvent, AutoResetEvent which are well documented.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜