Critical sections are not the way to solve this problem. A critical section is nothing more than a mutual exclusion device. It's intended to ensure that only one thread can be executing a particular piece of code at a given time. It's not intended to be used for sequencing, nor is it particularly good for that task. The problem is that you can't wait on a critical section without acquiring it.
Consider a case in which Thread B has to wait for Thread A to finish before continuing with its work. If you use a critical section (call it cs1
), then you have to ensure that Thread A acquires it before Thread B tries to acquire it. That means you have to make 100% sure that Thread A begins execution and acquires the critical section before Thread B can potentially acquire the critical section.
Event Objects, on the other hand, allow you to wait for an event or continue if the event has already occurred. So Thread B can wait on the event before Thread A even starts. And it will wait until Thread A (or somebody) sets the event. The problem you describe (thread B needing to wait for some event to happen) is exactly the type of thing that event objects were designed to solve.
Given 3 threads that process in parallel for some time, but at some point need to wait for some other event to happen, you'd write code to create and wait on the events. Briefly:
HANDLE event1_done = CreateEvent(...);
HANDLE event2_done = CreateEvent(...);
HANDLE event3_done = CreateEvent(...);
All events are manual reset, and their initial state is not signaled.
The main thread starts the three events. Then it waits on the third one to be finished:
WaitForSingleObject(event3_done, INFINITE);
The individual threads do their processing and wait on their respective events. Thread 1, of course, doesn't wait. It just does this:
// thread 1
// do processing
// then signal that it's finished
SetEvent(event1_done);
Thread 2 does its processing, waits on event1_done
, and then sets event2_done
:
// thread 2
// do processing
// wait for the first thread to complete
WaitForSingleObject(event1_done, INFINITE);
// do whatever
// and then signal that it's done
SetEvent(event2_done);
Thread 3 is just like Thread 2; only the event names have changed.
The difference between this method and using critical sections is that multiple threads could be waiting on the same event object. When that event is set, all of the threads waiting on that object are released. If you want only one of them released, then you'd use an auto reset event.
Also note that if you want to re-use those events, you'll need to reset them (call ResetEvent
). When you do that is up to you.