I think this is due to:
dwEvent = WaitForMultipleObjects(
EVENT_NUM, // number of objects in array
ghEvents, // array of objects
FALSE, // wait for any object (*)
INFINITE); // INFINITE wait
(*) Since you specify here that it shouldn't wait for all the events to become signalled it will return as soon as any of the events got signalled.
Then here:
for (i = 0; i < EVENT_NUM; i++)
CloseHandle(ghEvents[i]);
You close all (both) events. So what probably happens is something like this:
1. You start thread A.
2. You start thread B.
3. Thread A finishes, signals event 0.
4. You wait for any of 'event 0' or 'event 1' to get signalled, 'event 0' IS signalled by 'thread A', you go on
5. you close both 'event 0' and 'event 1'.
6. 'Thread B' gets to the point where it tries to signal 'event 1', since your "main thread" already destroyed this event, ERROR.
Try changing that FALSE to TRUE in the WaitForMultipleObjects call. Thread synchronization can be a pain in the you know what.