生产者-消费者模型是学习线程同步的经典模型,网上有关Windows版本的文章也有很多,但是你能找到的90%的都是有问题的
大部分都能很好的处理共享数据队列互斥访问,但是在判断队列空或者满的时候没有做任何线程保护,也就是说那样的示例是
没法用在实际商业项目中的,下面的例子用使用互斥量(Mutex)和信号量(Semaphore)来出实现生产者-消费者,互斥量用来
同步生产者和消费者线程同步访问数据队列的问题,信号量用来处理队列中资源个数的问题
首先创建1个互斥量
hMutex = CreateMutex(NULL, false, NULL);
创建2个信号量,一个用来表示队列剩余空间,一个表示队列中可用数据的个数,这里假定队列的容量是10
hProduceSemp = CreateSemaphore(NULL, 10, 10, NULL);
hConsumeSemp = CreateSemaphore(NULL, 0, 10, NULL);
其中hProduceSemp表示队列最大长度是10,当前可用10
hConsumeSemp表示对垒最大长度是10,当前可用是0(初始时刻我们还没有给队列中生产任何数据,可用数据当然就是0喽)
创建一个辅助的Struct用来从外部传入参数给线程处理函数
typedef struct ThreadData
{
CProductAndConsumer* pThis;
int ThreadIndex;
}ThreadData;
创建生产者和消费者处理线程
for (size_t i = 0; i < 2; i++)
{
ThreadData* pData = new ThreadData();
pData->pThis = this;
pData->ThreadIndex = i + 1;
CreateThread(NULL, 0, ProduceProc, (LPVOID)pData, 0, NULL);
}
for (size_t i = 0; i < 4; i++)
{
ThreadData* pData = new ThreadData();
pData->pThis = this;
pData->ThreadIndex = i + 1;
CreateThread(NULL, 0, ConsumeProc, (LPVOID)pData, 0, NULL);
}
实现生产者线程处理函数ProduceProc,和具体的生产过程
DWORD WINAPI CProductAndConsumer::ProduceProc(__in LPVOID lpParameter)
{
CTools::OutputDebugPrintf("ProduceProc enter\n");
ThreadData* pData = (ThreadData*)lpParameter;
CProductAndConsumer* pThis = pData->pThis;
while (!pThis->isQuit())
{
WaitForSingleObject(pThis->hProduceSemp, INFINITE);
pThis->Produce(pData->ThreadIndex);
ReleaseSemaphore(pThis->hConsumeSemp, 1, NULL);
Sleep(rand() % 900 + 100);
}
return 0;
}
// 生产
int CProductAndConsumer::Produce(int nThreadIndex)
{
WaitForSingleObject(hMutex, INFINITE);
srand(mProduceResIndex);
int nRandValue =rand() % 999 + 1000;
mRes[mProduceResIndex %10] = nRandValue;
CTools::OutputDebugPrintf("ProduceThread-%d count:%d Value:%d\n", nThreadIndex, mProduceResIndex, nRandValue);
mProduceResIndex++;
ReleaseMutex(hMutex);
return 0;
}
实现消费者处理函数和具体消费过程
DWORD WINAPI CProductAndConsumer::ConsumeProc(__in LPVOID lpParameter)
{
CTools::OutputDebugPrintf("ConsumeProc enter\n");
ThreadData* pData = (ThreadData*)lpParameter;
CProductAndConsumer* pThis = pData->pThis;
while (!pThis->isQuit())
{
WaitForSingleObject(pThis->hConsumeSemp, INFINITE);
pThis->Consume(pData->ThreadIndex);
ReleaseSemaphore(pThis->hProduceSemp, 1, NULL);
Sleep(rand()%900+100);
}
return 0;
}
// 消费
int CProductAndConsumer::Consume(int nThreadIndex)
{
WaitForSingleObject(hMutex, INFINITE);
CTools::OutputDebugPrintf("ConsumeThread-%d count:%d Value:%d\n", nThreadIndex, mConsumeResIndex, mRes[mConsumeResIndex%10]);
mConsumeResIndex++;
ReleaseMutex(hMutex);
return 0;
}
代码比较简单,看看就能懂
全部代码
头文件
class CProductAndConsumer
{
public:
CProductAndConsumer();
~CProductAndConsumer();
int Init();
private:
int Produce(int nThreadIndex);
int Consume(int nThreadIndex);
static DWORD WINAPI ProduceProc(__in LPVOID lpParameter);
static DWORD WINAPI ConsumeProc(__in LPVOID lpParameter);
bool isQuit();
private:
HANDLE hProduceSemp;
HANDLE hConsumeSemp;
HANDLE hMutex;
int mRes[10];
int mProduceResIndex;
int mConsumeResIndex;
};
实现文件
#include "CProductAndConsumer.h"
#include "CTools.h"
typedef struct ThreadData
{
CProductAndConsumer* pThis;
int ThreadIndex;
}ThreadData;
CProductAndConsumer::CProductAndConsumer()
{
mProduceResIndex = 0;
mConsumeResIndex = 0;
}
CProductAndConsumer::~CProductAndConsumer()
{
}
int CProductAndConsumer::Init()
{
hProduceSemp = CreateSemaphore(NULL, 10, 10, NULL);
hConsumeSemp = CreateSemaphore(NULL, 0, 10, NULL);
hMutex = CreateMutex(NULL, false, NULL);
for (size_t i = 0; i < 2; i++)
{
ThreadData* pData = new ThreadData();
pData->pThis = this;
pData->ThreadIndex = i + 1;
CreateThread(NULL, 0, ProduceProc, (LPVOID)pData, 0, NULL);
}
for (size_t i = 0; i < 4; i++)
{
ThreadData* pData = new ThreadData();
pData->pThis = this;
pData->ThreadIndex = i + 1;
CreateThread(NULL, 0, ConsumeProc, (LPVOID)pData, 0, NULL);
}
return 0;
}
DWORD WINAPI CProductAndConsumer::ProduceProc(__in LPVOID lpParameter)
{
CTools::OutputDebugPrintf("ProduceProc enter\n");
ThreadData* pData = (ThreadData*)lpParameter;
CProductAndConsumer* pThis = pData->pThis;
while (!pThis->isQuit())
{
WaitForSingleObject(pThis->hProduceSemp, INFINITE);
pThis->Produce(pData->ThreadIndex);
ReleaseSemaphore(pThis->hConsumeSemp, 1, NULL);
Sleep(rand() % 900 + 100);
}
return 0;
}
DWORD WINAPI CProductAndConsumer::ConsumeProc(__in LPVOID lpParameter)
{
CTools::OutputDebugPrintf("ConsumeProc enter\n");
ThreadData* pData = (ThreadData*)lpParameter;
CProductAndConsumer* pThis = pData->pThis;
while (!pThis->isQuit())
{
WaitForSingleObject(pThis->hConsumeSemp, INFINITE);
pThis->Consume(pData->ThreadIndex);
ReleaseSemaphore(pThis->hProduceSemp, 1, NULL);
Sleep(rand()%900+100);
}
return 0;
}
bool CProductAndConsumer::isQuit()
{
return false;
}
// 生产
int CProductAndConsumer::Produce(int nThreadIndex)
{
WaitForSingleObject(hMutex, INFINITE);
srand(mProduceResIndex);
int nRandValue =rand() % 999 + 1000;
mRes[mProduceResIndex %10] = nRandValue;
CTools::OutputDebugPrintf("ProduceThread-%d count:%d Value:%d\n", nThreadIndex, mProduceResIndex, nRandValue);
mProduceResIndex++;
ReleaseMutex(hMutex);
return 0;
}
// 消费
int CProductAndConsumer::Consume(int nThreadIndex)
{
WaitForSingleObject(hMutex, INFINITE);
CTools::OutputDebugPrintf("ConsumeThread-%d count:%d Value:%d\n", nThreadIndex, mConsumeResIndex, mRes[mConsumeResIndex%10]);
mConsumeResIndex++;
ReleaseMutex(hMutex);
return 0;
}