WaitHandle.WaitAll has a limit of 64 descriptors, which is obviously a huge limitation. On the other hand, this is a convenient way to wait for many signals in just one call. Thread.Join does not require the creation of additional WaitHandle instances. And since it can be called individually in each thread, the 64-character limit does not apply.
Personally, I have never used WaitHandle.WaitAll . I prefer a more scalable pattern when I want to wait for multiple signals. You can create a counting mechanism that counts up or down, and as soon as a certain value reaches you, you will report one common event. The CountdownEvent class conveniently packs it all into one class.
var finished = new CountdownEvent(1); for (int i = 0; i < NUM_WORK_ITEMS; i++) { finished.AddCount(); SpawnAsynchronousOperation( () => { try { // Place logic to run in parallel here. } finally { finished.Signal(); } } } finished.Signal(); finished.Wait();
Update:
The reason you want to signal an event from the main thread is subtle. Basically, you want to process the main thread as if it were just another work item. In the end, he, along with other real work items, works simultaneously.
Consider for a moment what can happen if we do not consider the main thread as a work item. It will go through one iteration of the for loop and add an account to our event (via AddCount ), indicating that we have one incomplete work item? Assume that SpawnAsynchronousOperation terminates and receives a work item in a queue in another thread. Now imagine if the main thread takes preventive measures before moving on to the next iteration of the loop. The thread executing the work item gets its share in the CPU and starts humming and actually completes the work item. A Signal call on a work item starts and reduces the count of pending work items to zero, which changes the CountdownEvent state to an alarm. Meanwhile, the main thread wakes up and goes through all iterations of the loop and calls the Wait call, but since the event was signaled ahead of time that it had passed, although there were still waiting work items.
Again, avoiding this subtle race condition is easy when you view the main thread as a work item. This is why the CountdownEvent initialized with a single counter, and the Signal method is called before Wait .
source share