Compare Join and WaitAll

For multiple threads to wait, can anyone compare the pros and cons of using WaitHandle.WaitAll and Thread.Join ?

+4
source share
3 answers

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 .

+3
source

I like @Brian's answer as a comparison of two mechanisms.

If you are on .Net 4, it would be useful to study the Task Parallel Library to achieve the Parellelism task through System.Threading.Tasks , which allows you to manage tasks from multiple threads at a higher level of abstraction. The signal that you asked in this question to control thread interactions is hidden or greatly simplified, and you can focus on correctly determining what each task consists of and how to coordinate them.

This may seem offtopic, but as Microsoft themselves say in MSDN docs:

in the .NET Framework 4, tasks are the preferred API for writing multi-threaded, asynchronous, and parallel code.

+1
source

The waitall mechanism includes kernel mode objects. I do not think this is true for the join mechanism. I would rather join, given the opportunity.

Technically, the two are not equivalent. IIRC Join can only work on one thread. Waitall can be used to signal several kernel objects.

0
source

All Articles