我修改了" Using Condition Variables" MSDN中的示例。我创建了几个线程,它们分别有自己的生产者/消费者。
但是当附加到调试器时,程序通常会挂起。它始终挂在SleepConditionVariableCS
。当我打破所有并继续调试时,程序将继续运行。我发现WakeAllConditionVariable没有唤醒一些线程调用SleepConditionVariableCS,对于Px在PExecutingTask-> BufferNotFull或PExecutingTask-> BufferNotEmpty已经是0x00000000(我认为这意味着条件变量被唤醒)。
如果没有附加到调试器,程序将不会挂起。
以前有人遇到过这个问题吗?怎么解决?
以下是代码:
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#define BUFFER_SIZE 100
DWORD WINAPI ProducerThreadProc (PVOID p);
DWORD WINAPI ConsumerThreadProc (PVOID p);
class ExecutingTask
{
public:
void Initialize()
{
InitializeConditionVariable (&BufferNotEmpty);
InitializeConditionVariable (&BufferNotFull);
InitializeCriticalSection (&BufferLock);
QueueSize = 0;
StopRequested = FALSE;
hProducer = CreateThread(NULL, 0, ProducerThreadProc, (PVOID)this, 0, NULL);
for (int i = 0; i < 20; i++)
{
PhConsumers[i] = CreateThread (NULL, 0, ConsumerThreadProc, (PVOID)this, 0, NULL);
}
}
void Stop()
{
EnterCriticalSection (&BufferLock);
StopRequested = TRUE;
LeaveCriticalSection (&BufferLock);
WakeAllConditionVariable (&BufferNotFull);
WakeAllConditionVariable (&BufferNotEmpty);
WaitForSingleObject(hProducer, INFINITE);
WaitForMultipleObjects(20, (HANDLE *)&PhConsumers, true, INFINITE);
CloseHandle(hProducer);
for (unsigned int i = 0; i < 20; i++)
{
CloseHandle(PhConsumers[i]);
}
}
public:
ULONG QueueSize;
CONDITION_VARIABLE BufferNotEmpty;
CONDITION_VARIABLE BufferNotFull;
CRITICAL_SECTION BufferLock;
BOOL StopRequested;
HANDLE PhConsumers[20];
HANDLE hProducer;
};
DWORD WINAPI ProducerThreadProc (PVOID p)
{
ExecutingTask* PExecutingTask = (ExecutingTask*)p;
while (true)
{
EnterCriticalSection (&PExecutingTask->BufferLock);
while (PExecutingTask->QueueSize >= BUFFER_SIZE && PExecutingTask->StopRequested == FALSE)
{
// Buffer is full - sleep so consumers can get items.
SleepConditionVariableCS (&PExecutingTask->BufferNotFull, &PExecutingTask->BufferLock, INFINITE);
}
if (PExecutingTask->StopRequested == TRUE)
{
LeaveCriticalSection (&PExecutingTask->BufferLock);
break;
}
// Produce an item.
PExecutingTask->QueueSize++;
LeaveCriticalSection (&PExecutingTask->BufferLock);
WakeConditionVariable (&PExecutingTask->BufferNotEmpty);
}
return 0;
}
DWORD WINAPI ConsumerThreadProc (PVOID p)
{
ExecutingTask* PExecutingTask = (ExecutingTask*)p;
while (true)
{
EnterCriticalSection (&PExecutingTask->BufferLock);
while (PExecutingTask->QueueSize == 0 && PExecutingTask->StopRequested == FALSE)
{
// Buffer is empty - sleep so producers can create items.
SleepConditionVariableCS (&PExecutingTask->BufferNotEmpty, &PExecutingTask->BufferLock, INFINITE);
}
if (PExecutingTask->StopRequested == TRUE)
{
LeaveCriticalSection (&PExecutingTask->BufferLock);
break;
}
// Consume an item.
PExecutingTask->QueueSize--;
LeaveCriticalSection (&PExecutingTask->BufferLock);
WakeConditionVariable (&PExecutingTask->BufferNotFull);
}
return 0;
}
DWORD WINAPI ThreadProc (PVOID p)
{
ExecutingTask task;
task.Initialize();
Sleep(1000);
task.Stop();
printf ("%u exit\n", &task);
return 0;
};
int main ( void )
{
HANDLE hTaskThreads[50];
for (int i = 0; i < 50; i++)
{
hTaskThreads[i] = CreateThread (NULL, 0, ThreadProc, NULL, 0, NULL);
}
WaitForMultipleObjects(50, hTaskThreads, true, INFINITE);
for (int i = 0; i < 50; i++)
{
CloseHandle(hTaskThreads[i]);
}
}