02-11-2019, 06:45 AM
1. The main macro exits when it started the last 4 threads. When it exits, sem destructor calls CloseHandle, making the handle invalid and its numeric value subject to use for another handle. If the main thread does not wait until other threads exit, other threads call ReleaseSemaphore with invalid or another (value reused) handle.
2, 3. If you know that threads never ever return or throw exception without calling ReleaseSemaphore, then call ReleaseSemaphore at the end instead of atend/#sub. Another way to ensure that ReleaseSemaphore is always called at the end - create a class that calls ReleaseSemaphore in destructor, and declare a variable of that class in the thread.
2, 3. If you know that threads never ever return or throw exception without calling ReleaseSemaphore, then call ReleaseSemaphore at the end instead of atend/#sub. Another way to ensure that ReleaseSemaphore is always called at the end - create a class that calls ReleaseSemaphore in destructor, and declare a variable of that class in the thread.