线程---条件变量,一次性初始化
2011-05-18 22:57 Clingingboy 阅读(1804) 评论(0) 编辑 收藏 举报
以SDK的生产者和消费者为例,两个是一个循环关系.
生产者的职责:
1.负责生产产品,如果产品的产量达到最高量了,就停止生产(没有消费者用,当然停掉了),即生产线暂时停工
2.当有消费者购买时,未达到最高产品数量的时候,则继续生产.
以上可以看到生产者生产东西是有条件的,即有人消费(废话,卖东西肯定得有人买了,有人购买就是生产的触发条件)
归纳为
生产者做了以下事情
1.东西卖不出去,停止生产
2.通知消费者,我有货快来买
3.有消费者买了产品,继续生产到最高产品数量
三者不断循环
同理消费者的逻辑也相似
1.没有产品,停止使用
2.通知生产者,东西卖完了,赶紧补货
3.生产者生产好产品,消费者继续使用
三者不断循环
那么假设生产者和消费者,各自为一个线程,当某些条件满足时就会阻塞自己(如东西卖不出去,停止生产;没有产品,停止使用),当打破这些条件时则继续执行,在现实生活中这很容易理解,换成代码比较晦涩.下面来看代码
先定义三个变量
CONDITION_VARIABLE BufferNotEmpty;
CONDITION_VARIABLE BufferNotFull;
CRITICAL_SECTION BufferLock;
必须要对变量进行初始化调用,然后有1个生产者和2个消费者,条件变量依赖于临界区(CRITICAL_SECTION)
InitializeConditionVariable (&BufferNotEmpty);
InitializeConditionVariable (&BufferNotFull);
InitializeCriticalSection (&BufferLock);
DWORD id;
HANDLE hProducer1 = CreateThread (NULL, 0, ProducerThreadProc, (PVOID)1, 0, &id);
HANDLE hConsumer1 = CreateThread (NULL, 0, ConsumerThreadProc, (PVOID)1, 0, &id);
HANDLE hConsumer2 = CreateThread (NULL, 0, ConsumerThreadProc, (PVOID)2, 0, &id);
来看生产者代码:
DWORD WINAPI ProducerThreadProc (PVOID p)
{
ULONG ProducerId = (ULONG)(ULONG_PTR)p;
while (true)
{
// Produce a new item.
Sleep (rand() % PRODUCER_SLEEP_TIME_MS);
ULONG Item = InterlockedIncrement (&LastItemProduced);
EnterCriticalSection (&BufferLock);
while (QueueSize == BUFFER_SIZE && StopRequested == FALSE)
{
// Buffer is full - sleep so consumers can get items.
SleepConditionVariableCS (&BufferNotFull, &BufferLock, INFINITE);
}
if (StopRequested == TRUE)
{
LeaveCriticalSection (&BufferLock);
break;
}
// Insert the item at the end of the queue and increment size.
Buffer[(QueueStartOffset + QueueSize) % BUFFER_SIZE] = Item;
QueueSize++;
TotalItemsProduced++;
printf ("Producer %u: item %2d, queue size %2u\r\n", ProducerId, Item, QueueSize);
LeaveCriticalSection (&BufferLock);
// If a consumer is waiting, wake it.
WakeConditionVariable (&BufferNotEmpty);
}
printf ("Producer %u exiting\r\n", ProducerId);
return 0;
}
当数量等于BUFFER_SIZE则罢工,否则的话生产出产品就通知消费者有货
while (QueueSize == BUFFER_SIZE && StopRequested == FALSE)
{
// Buffer is full - sleep so consumers can get items.
SleepConditionVariableCS (&BufferNotFull, &BufferLock, INFINITE);
}
// If a consumer is waiting, wake it.
WakeConditionVariable (&BufferNotEmpty);
消费者也是如此,没货就等待,当用完一个产品就通知生产者继续生产
while (QueueSize == 0 && StopRequested == FALSE)
{
// Buffer is empty - sleep so producers can create items.
SleepConditionVariableCS (&BufferNotEmpty, &BufferLock, INFINITE);
}
WakeConditionVariable (&BufferNotFull);
DWORD WINAPI ConsumerThreadProc (PVOID p)
{
ULONG ConsumerId = (ULONG)(ULONG_PTR)p;
while (true)
{
EnterCriticalSection (&BufferLock);
while (QueueSize == 0 && StopRequested == FALSE)
{
// Buffer is empty - sleep so producers can create items.
SleepConditionVariableCS (&BufferNotEmpty, &BufferLock, INFINITE);
}
if (StopRequested == TRUE && QueueSize == 0)
{
LeaveCriticalSection (&BufferLock);
break;
}
// Consume the first available item.
LONG Item = Buffer[QueueStartOffset];
QueueSize--;
QueueStartOffset++;
TotalItemsConsumed++;
if (QueueStartOffset == BUFFER_SIZE)
{
QueueStartOffset = 0;
}
printf ("Consumer %u: item %2d, queue size %2u\r\n",
ConsumerId, Item, QueueSize);
LeaveCriticalSection (&BufferLock);
// If a producer is waiting, wake it.
WakeConditionVariable (&BufferNotFull);
// Simulate processing of the item.
Sleep (rand() % CONSUMER_SLEEP_TIME_MS);
}
printf ("Consumer %u exiting\r\n", ConsumerId);
return 0;
}
附带Windows核心编程第5版(采用新api)以前的线程池资料
http://wenku.baidu.com/view/3df5000d6c85ec3a87c2c5c0.html
一次性初始化
以保证线程在调用资源时,确保资源已经被初始化,并且只初始化一次
InitHandleFunction 函数将只会触发一次,初始化的对象估计会与INIT_ONCE对象关联起来
// Global variable
INIT_ONCE g_InitOnce;
BOOL CALLBACK InitHandleFunction (
PINIT_ONCE InitOnce,
PVOID Parameter,
PVOID *lpContext)
{
HANDLE hEvent;
hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
if (NULL == hEvent)
{
return FALSE;
}
else
{
*lpContext = hEvent;
return TRUE;
}
}
HANDLE OpenEventHandleSync()
{
PVOID lpContext;
BOOL bStatus;
bStatus = InitOnceExecuteOnce(&g_InitOnce,
InitHandleFunction,
NULL,
&lpContext);
if (bStatus)
{
return (HANDLE)lpContext;
}
else
{
return (INVALID_HANDLE_VALUE);
}
}
异步初始化:
其甚至没有回调函数,并且前后有两个InitOnceBeginInitialize函数,用InitOnceComplete来通知初始化完毕
// Global variable
INIT_ONCE g_InitOnce;
HANDLE OpenEventHandleAsync()
{
PVOID lpContext;
BOOL fStatus;
BOOL fPending;
HANDLE hEvent;
fStatus = InitOnceBeginInitialize(&g_InitOnce,
INIT_ONCE_ASYNC,
&fPending,
&lpContext);
if (!fStatus)
{
return (INVALID_HANDLE_VALUE);
}
// Initialization has already completed.
if (!fPending)
{
return (HANDLE)lpContext;
}
hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
if (NULL == hEvent)
{
return (INVALID_HANDLE_VALUE);
}
fStatus = InitOnceComplete(&g_InitOnce,
INIT_ONCE_ASYNC,
(PVOID)hEvent);
if (fStatus)
{
return hEvent;
}
// Initialization has already completed. Free the local event.
CloseHandle(hEvent);
// Retrieve the final context data.
fStatus = InitOnceBeginInitialize(&g_InitOnce,
INIT_ONCE_CHECK_ONLY,
&fPending,
&lpContext);
if (fStatus && !fPending)
{
return (HANDLE)lpContext;
}
else
{
return INVALID_HANDLE_VALUE;
}
}
参考:
http://msdn.microsoft.com/zh-cn/magazine/cc163405.aspx#S3