您的位置:首页 > 其它

生产者消费者多缓冲区实现

2015-01-13 19:19 295 查看
#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,这样我们就完成了生产者消费者的线程模型
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: