DWORD WINAPI WriterThread(PVOID pvParam) { int nThreadNum = PtrToUlong(pvParam); HWND hWndLB = GetDlgItem(g_hWnd, IDC_CLIENTS); for (int nRequestNum = 1; !g_fShutdown; nRequestNum++) { CQueue::ELEMENT e = { nThreadNum, nRequestNum }; // Require access for writing AcquireSRWLockExclusive(&g_srwLock); // If the queue is full, fall asleep as long as the condition variable // is not signaled // Note: During the wait for acquiring the lock, // a stop might have been received if (g_q.IsFull() & !g_fShutdown) { // No more room in the queue AddText(hWndLB, TEXT("[%d] Queue is full: impossible to add %d"), nThreadNum, nRequestNum); // --> Need to wait for a reader to empty a slot before acquiring // the lock again SleepConditionVariableSRW(&g_cvReadyToProduce, &g_srwLock, INFINITE, 0); } // Other writer threads might still be blocked on the lock // --> Release the lock and notify the remaining writer threads to quit if (g_fShutdown) { // Show that the current thread is exiting AddText(hWndLB, TEXT("[%d] bye bye"), nThreadNum); // No need to keep the lock any longer ReleaseSRWLockExclusive(&g_srwLock); // Signal other blocked writers threads that it is time to exit WakeAllConditionVariable(&g_cvReadyToProduce); // Bye bye return(0); } else { // Add the new ELEMENT into the queue g_q.AddElement(e); // Show result of processing element AddText(hWndLB, TEXT("[%d] Adding %d"), nThreadNum, nRequestNum); // No need to keep the lock any longer ReleaseSRWLockExclusive(&g_srwLock); // Signal reader threads that there is an element to consume WakeAllConditionVariable(&g_cvReadyToConsume); // Wait before adding a new element Sleep(1500); } } // Show that the current thread is exiting AddText(hWndLB, TEXT("[%d] bye bye"), nThreadNum); return(0); }