实现一个线程安全的队列,并模拟进行生产者-消费者问题

/************************Produce and Consume.cpp***********************/
#include
#include
#include
#include
#include
#include

#define INTE_PER_SEC 1000   //每秒时钟中断数目
#define MAX_BUFFER_NUM 10   //最大临界区数
#define MAX_THREAD_NUM 64   //生产者和消费者的最大线程数目

struct ThreadInfo
{
	int serial;              //线程序号
	char entity;             //线程类别(判断是生产者线程还是消费者线程)
	double delay;            //线程延迟
	int thread_request [MAX_THREAD_NUM];//线程请求队列
	int n_request;           //消费者请求消费产品的个数
};

CRITICAL_SECTION PC_Critical[MAX_BUFFER_NUM];//临界区对象的声明,用于管理缓冲区的互斥访问
int      Buffer_Critical[MAX_BUFFER_NUM];   //缓冲区声明,用于存放产品
HANDLE   h_Thread[MAX_THREAD_NUM];          //用于存放每个线程句柄的数组
ThreadInfo Thread_Info[MAX_THREAD_NUM];     //线程信息数组
HANDLE   empty_semaphore;                   //信息量
HANDLE   h_mutex;                           //互斥量
DWORD    n_Thread=0;                        //实际的线程数目
DWORD    n_Buffer_or_Critical;              //实际的缓冲区或者临界区数目
HANDLE   h_Semaphore[MAX_THREAD_NUM];       //允许消费者开始消费的信号量

/************************************************************************/
//生产者消费者及辅助函数的定义
//确认是否还有对同一产品的消费请求未执行
bool IfInOtherRequest(int req)
{
	for(int i=0;iserial;
	m_delay=(DWORD)(((ThreadInfo*)(p))->delay*INTE_PER_SEC);
	Sleep(m_delay);  //延迟等待m_delay时间

	//开始请求生产
	printf("Producer  %d  sents the producing require.\n",m_serial);
	//确认有空缓冲区可供生产,同时将空位置数empty减1;用于生产者和消费者的同步
	wait_for_semaphore=WaitForSingleObject(empty_semaphore,-1);

	//互斥访问下一个可用于生产的空临界区,实现消费者之间的互斥
	wait_for_mutex=WaitForSingleObject(h_mutex,-1);
    //找出当前可以进行产品生产的空缓冲区位置
	int ProducePos=FindProducePosition();
	//释放互斥对象的所有权
	ReleaseMutex(h_mutex);

	//生产者在获得自己的空位置并做上标记后,以下的生产操作在生产者之间可以并发
	//在核心生产步骤中,程序将生产者的ID作为产品编号放入,方便消费者识别
	printf("Producer  %d  begins to produce at position %d ...\n",m_serial,ProducePos);
	Buffer_Critical[ProducePos]=m_serial;
	printf("Producer  %d  finished producing.\n",m_serial);
	printf("Position[ %d ]:%d.\n",ProducePos,Buffer_Critical[ProducePos]);

	//使生产者生产产品的缓冲区可以被多个消费者使用,实现生产者与消费者同步
	ReleaseSemaphore(h_Semaphore[m_serial],n_Thread,NULL);
}

//消费者线程
void Consume(void *p)
{
	int m_serial;              //消费者序号
	int	m_requestNum;          //消费者请求消费产品的数目
	int m_thread_request[MAX_THREAD_NUM]; //消费者线程的请求队列
	DWORD wait_for_semaphore;  //信号量
	DWORD m_delay;             //延迟时间

	//从参数中获得信息
	m_serial=((ThreadInfo*)(p))->serial;
	m_delay=(DWORD)(((ThreadInfo*)(p))->delay*INTE_PER_SEC);
	m_requestNum=((ThreadInfo*)(p))->n_request;
	for(int i=0;ithread_request[i];
	}
	Sleep(m_delay);     //延迟等待m_delay时间

	//循环进行所需要产品的消费
	for(i=0;ithread_request[i]=-1;
		if(!IfInOtherRequest(m_thread_request[i]))
		{   //不同消费者对同一产品的消费请求已执行完毕
			Buffer_Critical[BufferPos]=-1;//标记缓冲区为空
			printf("Consumer  %d  finished consuming product %d.\n",m_serial,m_thread_request[i]);
			printf("Position[ %d ]:%d.\n",BufferPos,Buffer_Critical[BufferPos]);
			ReleaseSemaphore(empty_semaphore,1,NULL);
		}
		else
		{
			printf("Consumer  %d  finished consuming product %d.\n",m_serial,m_thread_request[i]);
		}
		//离开临界区
		LeaveCriticalSection(&PC_Critical[BufferPos]);
	}
}

/************************************************************************/
//生产者--消费者处理函数
void PC(char *file)
{
	DWORD wait_for_all;  //等待所有线程结束
	ifstream inFile;
	int i,j;

	//初始化临界区
	for(i=0;i>n_Buffer_or_Critical;
	while(inFile)
	{   //读入每一个生产者、消费者的信息
		inFile>>Thread_Info[n_Thread].serial;
		inFile>>Thread_Info[n_Thread].entity;
		inFile>>Thread_Info[n_Thread].delay;
		char c;
		inFile.get(c);
		while(c!='\n'&&!inFile.eof())
		{
			inFile>>Thread_Info[n_Thread].thread_request[Thread_Info[n_Thread].n_request++];
			inFile.get(c);
		}
		n_Thread++;
	}

	//创建在模拟过程中的信号量
	empty_semaphore=CreateSemaphore(NULL,n_Buffer_or_Critical,n_Buffer_or_Critical,"semaphore_for_empty");
	h_mutex=CreateMutex(NULL,FALSE,"mutex_for_update");

	//用线程的ID号来为相应的生产线程的产品生产和消费时所使用的同步信号量命名
	for(i=0;i<(int)n_Thread;i++)
	{
		std::string lp="semaphore_for_produce_";
		int temp=i;
		while(temp)
		{
			char c=(char)(temp%10);
			lp+=c;
			temp/=10;
		}
		h_Semaphore[i+1]=CreateSemaphore(NULL,0,n_Thread,lp.c_str());
	}

	for(i=0;i<(int)n_Thread;i++)
	{
		if(Thread_Info[i].entity=='P')
		{   //创建生产者线程
			h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(Produce),&(Thread_Info[i]),0,NULL);
		}
		else
		{   //创建消费者线程
			h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(Consume),&(Thread_Info[i]),0,NULL);
		}
	}
	//等待所有线程结束
	wait_for_all=WaitForMultipleObjects(n_Thread,h_Thread,TRUE,-1);
	printf("\nAll Producer and Consumer have finished operating.\n");
}

/************************************************************************/
//主函数
int main(int argc,char*argv[])
{
	char ch;
	FILE *fp;
	fp=fopen("test.txt","r");
	if(fp==NULL)
	{
		printf("不能打开测试文件\n");
		return(0);
	}
	if((ch=fgetc(fp))==EOF)
	{
		printf("测试文件为空\n");
		return(0);
	}
	printf("*****************输入的测试文件如下*********************\n\n");
	while(ch!=EOF)
	{
		printf("%c",ch);
		ch=fgetc(fp);
	}

	printf("\n\n**************生产者--消费者测试结果如下****************\n\n");
	PC("test.txt");
	printf("\nPress any key to continue:");
    _getch();
	system("cls");
	return 0;
}

你可能感兴趣的:(实现一个线程安全的队列,并模拟进行生产者-消费者问题)