Given the above, we change to code to get the program to run. N.B. make sure you compile the code as a multi-threaded app.
const long MAXTHREADS = 100L;
const long MAXACTIVETHREADS = 20L;
int nThread = 0;
int nReleased = 0;
long lActiveThreads = 0L;
long lPreviousCount = 0L;
HANDLE hSemaphore = 0;
HANDLE hThread = 0;
const char *pSemaphoreName = "CreateThreadSemaphore";
bool Initialize()
{
bool bResult = false;
hSemaphore = ::CreateSemaphore(NULL, 0, MAXACTIVETHREADS, pSemaphoreName);
bResult = (0 != hSemaphore);
if (!bResult) {
// TODO: report error from GetLastError()
}
return bResult;
}
DWORD WINAPI Start( LPVOID lpParam )
{
// block til semaphore signals
::WaitForSingleObject(hSemaphore, INFINITE);
printf("End thread %d\n", GetCurrentThreadId());
--lActiveThreads;
++nReleased;
::ReleaseSemaphore(hSemaphore, 1, &lPreviousCount);
return TRUE;
}
void StartSimulation()
{
while (nThread < MAXTHREADS) {
if (lActiveThreads < MAXACTIVETHREADS) {
DWORD dwThreadID = 0;
hThread = ::CreateThread(NULL, 0, Start, NULL, 0, &dwThreadID);
if (!hThread) {
// TODO: report error from GetLastError()
} else {
printf("Start thread %d\n", dwThreadID);
::CloseHandle(hThread); // throw away thread handle
++lActiveThreads;
++nThread;
}
} else {
::ReleaseSemaphore(hSemaphore, 1, &lPreviousCount);
}
}
// wait for all threads to end
while (lActiveThreads) {
::ReleaseSemaphore(hSemaphore, 1, &lPreviousCount);
}
// destroy hSemaphore
::CloseHandle(hSemaphore);
printf("Created %d threads.\n"
"Release %d threads.\n"
"PreviousCount %ld\n", nThread, nReleased, lPreviousCount);
}
int main()
{
if (Initialize())
StartSimulation();
return 0;
}
I changed variable names and removed unnecessary code but didn't implement all the changes I indicated. The output should give you some idea of how running threads behave.