Windows环境下消费者和生产者简单实现
最近想实现个windows下面简单的线程池,代码已经写了一部分了,需要用到条件变量,本人参考了下《windows核心编程》里面有讲解,打算通过一个生产者和消费者模型demo来具体了解下如何使用这些接口。
首先讲解下需要用到的关于条件变量MSDN描述:
Condition variables are synchronization primitives that enable threads to wait until a particular condition occurs.
Condition variables are user-mode objects that cannot be shared across processes.
因为在我们的生产者和消费者模型中,需要考虑到如果消费者没有产品可取的时候,则需要等待生产者生产出产品以后再进行获取,而生产者在如果生产产品过多了的话,也需要等到消费者消费一部分产品以后,再进行生产,所以这个时候就要用到条件变量。
下面介绍下条件变量的使用:CONDITION_VARIABLE结构、InitializeConditionVariable、SleepConditionVariableCS和WakeConditionVariable 参考:https://msdn.microsoft.com/en-us/library/windows/desktop/ms682052(v=vs.85).aspx
CONDITION_VARIABLE就如CRITICAL_SECTION结构一样,通过使用InitializeConditionVariable进行初始化。
InitializeConditionVariable: Initializes a condition variable.
prototype:
VOID WINAPI InitializeConditionVariable( _Out_ PCONDITION_VARIABLE ConditionVariable );
usage:
InitializeConditionVariable(&g_conditionVaraible);
SleepConditionVariableCS: Sleeps on the specified condition variable and releases the specified critical section as an atomic operation.
prototype:
BOOL WINAPI SleepConditionVariableCS( _Inout_ PCONDITION_VARIABLE ConditionVariable, //A pointer to the condition variable. This variable must be initialized _Inout_ PCRITICAL_SECTION CriticalSection, //A pointer to the critical section object. This critical section must be entered exactly once by the caller at the time SleepConditionVariableCS is called _In_ DWORD dwMilliseconds //The time-out interval, in milliseconds,If dwMilliseconds is INFINITE, the function's time-out interval never elapses. );
usage:
SleepConditionnVariableCS(&g_conditionVariable, &g_criticalSection, INFINITE);
WakeConditionVariable: Wake a single thread waiting on the specified condition variable.
prototype:
VOID WINAPI WakeConditionVariable( _Inout_ PCONDITION_VARIABLE ConditionVariable );
usage:
WakeConditionVariable(&g_conditionVariable);
下面是demo:
1 #include "stdafx.h" 2 #include <windows.h> 3 #include <queue> 4 using namespace std; 5 6 #define BUFFER_SIZE 10 7 8 queue<char> g_character; //产品容器 9 volatile int g_count = 0; //产品容器数量 10 11 int g_consumCount; //消费者消费的总数量,如果消费完,则进行线程退出 12 13 CONDITION_VARIABLE g_emptyCond; 14 CONDITION_VARIABLE g_fullCond; 15 CRITICAL_SECTION g_bufferMutex; 16 17 //生产者生产“A-Za-z”52个字符产品, 18 DWORD WINAPI ThreadProducer(void* args) 19 { 20 char c = 'A'; 21 for (int i = 0; i < 52; ++i) 22 { 23 EnterCriticalSection(&g_bufferMutex); 24 while (BUFFER_SIZE == g_count) // 问题一:这里用的是while,而不是if 25 { 26 SleepConditionVariableCS(&g_fullCond, &g_bufferMutex, INFINITE); //如果容器放不下,生产者得停下来,让消费者消费了一部分产品后,给我们发信号。 27 } 28 fprintf(stdout, "P:%c\n", c); 29 g_character.push(c); 30 g_count++; 31 32 LeaveCriticalSection(&g_bufferMutex); 33 WakeConditionVariable(&g_emptyCond); // 我们得跟Consumer发信号,说缓冲区已经有产品了 34 c++; 35 if ('Z' + 1 == c) 36 { 37 c = 'a'; 38 } 39 } 40 41 return 0; 42 } 43 44 //消费者依次从产品容器中取出产品,进行打印 45 DWORD WINAPI ThreadConsumer(void* args) 46 { 47 int index = 0; 48 49 while (g_consumCount <= 52) 50 { 51 EnterCriticalSection(&g_bufferMutex); 52 g_consumCount++; 53 if (g_consumCount > 52) 54 { 55 LeaveCriticalSection(&g_bufferMutex); 56 break; 57 } 58 59 while (0 == g_count) 60 { 61 SleepConditionVariableCS(&g_emptyCond, &g_bufferMutex, INFINITE); 62 } 63 64 char c= g_character.front(); 65 g_character.pop(); 66 fprintf(stdout, "C:%c\n", c); 67 g_count--; 68 69 LeaveCriticalSection(&g_bufferMutex); 70 WakeConditionVariable(&g_fullCond); //如果产品消费了,给g_fullCond发信号,说我们腾空了位置,你又可以放产品了。 71 } 72 return 0; 73 } 74 75 int _tmain(int argc, _TCHAR* argv[]) 76 { 77 InitializeCriticalSection(&g_bufferMutex); 78 InitializeConditionVariable(&g_fullCond); 79 InitializeConditionVariable(&g_emptyCond); 80 HANDLE thr[3]; 81 thr[0] = CreateThread(NULL, 0, ThreadProducer, NULL, 0, NULL); 82 thr[1] = CreateThread(NULL, 0, ThreadConsumer, NULL, 0, NULL); 83 thr[2] = CreateThread(NULL, 0, ThreadConsumer, NULL, 0, NULL); 84 WaitForMultipleObjects(3, thr, TRUE, INFINITE); 85 86 DeleteCriticalSection(&g_bufferMutex); 87 system("pause"); 88 return 0; 89 }
代码说明:
1. 代码中注释的问题一 参见:https://msdn.microsoft.com/en-us/library/windows/desktop/ms686301(v=vs.85).aspx
Condition variables are subject to spurious wakeups (those not associated with an explicit wake) and stolen wakeups (another thread manages to run before the woken thread). Therefore, you should recheck a predicate (typically in a while loop) after a sleep operation returns.

浙公网安备 33010602011771号