#include<stdio.h>
#include<Windows.h>
#include<process.h>
int gBuffer=0;//全局变量,缓冲区
HANDLE g_EventBufferEmpty,g_EventBufferFull;
const int END_PRODUCE_NUMBER=10;
//生产者线程
DWORD ProducerThread(PVOID pm)
{
for(int i=1;i<=END_PRODUCE_NUMBER;i++)
{
::WaitForSingleObject(g_EventBufferEmpty,INFINITE);
gBuffer=i;
printf("生产者放入数据%d\n",gBuffer);
::SetEvent(g_EventBufferFull);
}
return 0;
}
//消费者线程
DWORD ConsumerThread(PVOID pm)
{
while(gBuffer!=END_PRODUCE_NUMBER)
{
//等待生产者线程写入数据
::WaitForSingleObject(g_EventBufferFull,INFINITE);
printf("消费者从缓冲区中取出数据%d\n",gBuffer);
SetEvent(g_EventBufferEmpty);
}
return 0;
}
int main()
{
g_EventBufferEmpty=CreateEvent(NULL,false,TRUE,NULL);
g_EventBufferFull=CreateEvent(NULL,false,false,NULL);
HANDLE hThread[2]={NULL};
DWORD ProduceID;
DWORD ConsumerID;
hThread[0]=::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ProducerThread,NULL,0,&ProduceID);
hThread[1]=::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ConsumerThread,NULL,0,&ConsumerID);
::WaitForMultipleObjects(2,hThread,true,INFINITE);
CloseHandle(hThread[0]);
CloseHandle(hThread[1]);
CloseHandle(g_EventBufferEmpty);
CloseHandle(g_EventBufferFull);
}
PS:在但缓冲区的环境下,我们只需要两个互斥变量,一个用来通知消费者消费gEventBufferFull,一个用于通知生产者生产gEventBufferEmpty,这样我们就可以实现了,而在多缓冲区的环境下使用互斥变量则有写捉襟见肘,而是需要使用可以计数的信号量来进行缓冲区的作用代码如下:
//如果有两个缓冲区多个生产者,多个消费者呢?
#include<Windows.h>
#include<iostream>
#include<process.h>
#include<vector>
using namespace std;
const int END_PRODUCE_NUMBER=8;
const int BUFFER_SIZE=4;
int g_i=0,g_j=0;
int gBuffer[BUFFER_SIZE]={0};
//设置信号量和关键段
CRITICAL_SECTION g_cs;
HANDLE g_SemphBufferEmpty=0,g_SemphBufferFull=0;
int mm[4]={0};
int a=0;
//生产者线程
DWORD Produce(PVOID pm)
{
for(int i=1;i<=END_PRODUCE_NUMBER;i++)
{
::WaitForSingleObject(g_SemphBufferEmpty,INFINITE);
//互斥访问的代码段
::EnterCriticalSection(&g_cs);
if(mm[g_i]!=1)
{
gBuffer[g_i]=i;
cout<<"生产者线程放入第"<<g_i<<"个缓冲池中的数据:"<<gBuffer[g_i]<<endl;
mm[g_i]=1;
}
g_i=(1+g_i)%BUFFER_SIZE;
::LeaveCriticalSection(&g_cs);
::ReleaseSemaphore(g_SemphBufferFull,1,NULL);
}
cout<<"生产者完成任务\n";
a=1;
return 0;
}
//消费者线程
DWORD Consumer(LPVOID pm)
{
//只要有我们就可以进行消费
while(TRUE)
{
::WaitForSingleObject(g_SemphBufferFull,INFINITE);
::EnterCriticalSection(&g_cs);
//取出第一个可用数据
for(int i=0;i<4;i++)
{
if(mm[i]==1)
{
cout<<"消费者线程取出第"<<i<<"个缓冲池中的数据:"<<gBuffer[i]<<endl;
mm[i]=0;
break;
}
}
::LeaveCriticalSection(&g_cs);
::ReleaseSemaphore(g_SemphBufferEmpty,1,NULL);
::Sleep(100);
int hh=0;
for(int i=0;i<4;i++)
{
if(mm[i]==0)
hh++;
}
if(hh==4&&a==1)
{
break;
}
}
cout<<"消费者完成任务"<<endl;
return 0;
}
int main()
{
//开始初始化代码段
::InitializeCriticalSection(&g_cs);
//初始化信号量
g_SemphBufferEmpty=::CreateSemaphoreA(NULL,4,4,NULL);
g_SemphBufferFull=::CreateSemaphoreA(NULL,0,4,NULL);
HANDLE hThread[3];
DWORD ThreadId;
hThread[0]=::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Consumer,NULL,0,&ThreadId);
hThread[1]=::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Produce,NULL,0,&ThreadId);
hThread[2]=::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Produce,NULL,0,&ThreadId);
::WaitForMultipleObjects(3,hThread,true,INFINITE);
for(int i=0;i<3;i++)
{
CloseHandle(hThread[i]);
}
CloseHandle(g_SemphBufferFull);
CloseHandle(g_SemphBufferEmpty);
::DeleteCriticalSection(&g_cs);
}
思路:主要就是最大值是4的信号量,我们根据这个信号量进行缓冲区的设置除了4个缓冲区gBuffer[4]以外还有一个对着4个缓冲区标志的索引mm[4],如果第i个缓冲区已经被使用那么mm[i]就为1,如果消费者对第j个缓冲区进行了消费,那么mm[j]=0;
每次生产者对缓冲区操作的时候需要检测mm相对应位置上的值是不是0,每次消费者对缓冲区读取的时候需要检测mm对应的值是不是1,这样我们就完成了生产者消费者的线程模型