Windows下实现生产者-消费者模型

要求

  • 在 windows 环境下,利用高级语言编程环境(限定为 VS 环境或 VC 环境)调用 CreateThread 函数和相关的同步函数,模拟实现“生产者-消费者”问题。“生产者-消费者”模拟实验的具体要求见后面附件。
    在这里插入图片描述

知识点

  • CRITICAL_SECTION cs : 创建一个临界区变量,其中EnterCriticalSection(&cs)LeaveCriticalSection(&cs)之间的区域就是临界区,临界资源是一次仅允许一个进程或线程使用的共享资源,这样就保证了不能同时进行生产和消费操作。
  • CreateEvent()函数:

HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,// 安全属性
BOOLbManualReset,// 复位方式,如果是TRUE,那么必须用ResetEvent函数来手工将事件的状态复原到无信号状态,使用ResetEvent()重置信号状态。如果设置为FALSE,当一个等待线程被释放以后,系统将会自动将事件状态复原为无信号状态。
BOOLbInitialState,// 初始状态,如果为TRUE,初始状态为有信号状态;否则为无信号状态。
LPCTSTRlpName // 对象名称
);

解析

  • 定义全局变量
    在这里插入图片描述
  • 生产者进程
    在这里插入图片描述
  • 消费者进程
    在这里插入图片描述
  • 创建两个生产者线程、三个消费者线程
    在这里插入图片描述

结果分析

  • 输出
    如图所示,生产者生产的对应数据永远在消费数据之前,且因为我把缓冲区当做一个队列处理,所以生产数据的顺序与消费数据的顺序对应。还能看出生产者1生产的数据在1000-1999内,生产者2生产数据在2000-2999内,符合题目要求。
    在这里插入图片描述
  • 文件输出
    如图所示,可知文件中记录的信息与控制台中输出的信息一样,文件写入无误。
    在这里插入图片描述

完整源码

#include<stdio.h>
#include<Windows.h>
#include <stdlib.h>
#include <time.h>
#include <io.h>
const int PRODUCT_NUM = 100;//产品数量
CRITICAL_SECTION cs;//定义临界区全局变量
HANDLE emptyEvent;//存在空位事件
HANDLE fullEvent;//存在数据事件
static int full = 0;//缓冲区中数据个数
static int empty = 10;//缓冲区中空位数量
static int Buffer[10];//存储数据的缓冲区
static int len = 10;//缓冲区长度
//将缓冲区看成一个队列
static int tail = -1;//缓冲区尾指针
static int head = 0;//缓冲区头指针
//产品与消费计数器
static int producerCount = 0;
static int consumerCount = 0;
//写入文件
static FILE* file;
int P(int *i) {
	return --*i;
}
int V(int *i) {
	return ++*i;
}
DWORD  WINAPI ProducerThread(void* a) {
		int data = 0;
		int* dataRange = (int *)a;//数据范围
	    while(TRUE) {
			if (producerCount >= PRODUCT_NUM) {
				break;
			}
		//以下两步相当于P操作
		P(&empty);
		//没有空位,等待消费者消费数据才能往下进行
		if (empty <= 0) {
			WaitForSingleObject(emptyEvent, INFINITE);
		}
		//进入临界区
		EnterCriticalSection(&cs);
		data = rand() % (dataRange[1] - dataRange[0] + 1) + dataRange[0];//随机数据
		Buffer[(++tail) % len] = data;
		printf("生产者%d生产第%d个数据%d.\n",dataRange[2], ++producerCount, data);
		//写入文件
		fprintf(file, "生产者%d生产第%d个数据%d.\n", dataRange[2], producerCount, data);
		LeaveCriticalSection(&cs);
		Sleep(rand() % 100 + 1);//随机睡眠1-100ms
		V(&full);
		if (full > 0) {
			SetEvent(fullEvent);
		}
	}
	return 0;
}
DWORD WINAPI ConsumerThread(void* a) {
	 int data = 0;
	 int *flag = (int *)a;//消费者编号
	 while(TRUE) {
		 if (consumerCount >= PRODUCT_NUM) {
			 break;
		 }
		//以下两步相当于P操作
		P(&full);
		//没有数据,等待生产者生产数据才能往下进行
		if (full <= 0) {
			WaitForSingleObject(fullEvent, INFINITE);
		}
		//进入临界区
		EnterCriticalSection(&cs);
		data = Buffer[head % len];
		head = (head + 1) % len;
		printf("\t\t\t消费者%d消费第%d个数据%d.\n",*flag, ++consumerCount, data);
		//写入文件
		fprintf(file, "\t\t\t消费者%d消费第%d个数据%d.\n", *flag, consumerCount, data);
		LeaveCriticalSection(&cs);
		Sleep(rand() % 100 + 1);//随机睡眠1-100ms
		V(&empty);
		if (empty > 0) {
			SetEvent(emptyEvent);
		}
	}
	return 0;
}

int main() {
	srand((unsigned int)(time(NULL)));
	InitializeCriticalSection(&cs);//初始化临界区变量
	emptyEvent = CreateEvent(NULL, false, true, NULL);
	fullEvent = CreateEvent(NULL, false, false, NULL);
	static char* fileName = "E://操作系统原理练习/第二次上机/log.txt";
	fopen_s(&file, fileName, "r+");
	HANDLE handle[5];
	int a1[3] = { 1000,1999,1};//生产者1产生数据范围1000-1999,最后一个数是对应编号
	int a2[3] = { 2000, 2999,2};//生产者2产生数据范围2000-2999,最后一个数是对应标号
	//创建生产线程
	handle[0] = CreateThread(NULL, 0, ProducerThread, a1, 0, NULL);
	handle[1] = CreateThread(NULL, 0, ProducerThread, a2, 0, NULL);
	//对消费者进行标号
	int *flag1 = (int *)malloc(sizeof(int *)), *flag2 = (int *)malloc(sizeof(int *)), *flag3 = (int *)malloc(sizeof(int *));
	*flag1 = 1;
	*flag2 = 2;
	*flag3 = 3;
	//消费者线程
	handle[2] = CreateThread(NULL, 0, ConsumerThread, flag1, 0, NULL);
	handle[3] = CreateThread(NULL, 0, ConsumerThread, flag2, 0, NULL);
	handle[4] = CreateThread(NULL, 0, ConsumerThread, flag3, 0, NULL);
	WaitForMultipleObjects(5, handle, TRUE, INFINITE);
	 
	fclose(file);
	getchar();
	return 0;
}
  • 9
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值