核心代码:
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<string.h>
#include<windows.h>
#define dataBufferSize 2 //缓冲区数目
#define processNum 4 //进程数量(生产者、消费者进程总数目)
typedef struct Seamphore //信号量
{
int value; //信号量的值
int *pcq; //信号量队列指针
} Seamphore;
int producerCongestionQueue[processNum]; //等待信号量empty的阻塞队列
int consumerCongestionQueue[processNum]; //等待信号量full的阻塞队列
int shareCongestionQueue[processNum]; //等待信号量mutex的阻塞队列
Seamphore empty={dataBufferSize,producerCongestionQueue}; // empty:空缓冲区数目
Seamphore full={0,consumerCongestionQueue}; // full:缓冲区内可用的产品
Seamphore mutex={1,shareCongestionQueue}; //mutex:互斥信号量
struct DataBuffer //缓冲区
{
int buffer[dataBufferSize];
int count; //当前产品数量
}dataBuffer;
typedef struct Process //进程PCB
{
char name[10]; //进程名
int roleFlag; //进程类型(1: 生产者 0: 消费者)
int currentState; //进程状态(1: 就绪态 0: 阻塞态)
int currentStep; //断点
int data; //临时数据
int code; //进程编号
}Process;
Process process[processNum]; //进程集合
void moveDataForward()
{
int i;
for (i = 0; i <dataBuffer.count; i++)
dataBuffer.buffer[i] = dataBuffer.buffer[i+1];
}
void push(int data) //产品送入缓冲区
{
dataBuffer.buffer[dataBuffer.count++] = data;
}
int pop() //从缓冲区取出产品
{
int data = dataBuffer.buffer[0];
dataBuffer.count--;
moveDataForward();
return data;
}
void initProcess() { //初始化进程集合
int i;
char digitTemp[5];
srand(time(NULL));
for (i = 0; i <processNum; i++) {
process[i].roleFlag = rand()%2; // 随机指定当前进程为生产者或消费者
if (process[i].roleFlag)
strcpy(process[i].name, "生产者");
else
strcpy(process[i].name, "消费者");
strcat(process[i].name, itoa(i+1, digitTemp, 10));
process[i].currentState = 1;
process[i].currentStep = 1;
process[i].code = i + 1;
producerCongestionQueue[i] = 0;
consumerCongestionQueue[i] = 0;
shareCongestionQueue[i] = 0;
}
}
void wakeup(int *pcq) { //唤醒进程
int code = pcq[0] - 1; //取出队首进程
process[code].currentState = 1; //进程置为就绪态
//当进程被唤醒后继续执行任务
if (process[code].roleFlag == 1) { //生产者
if (process[code].currentStep == 2) {
printf("%20s: 该进程被唤醒!申请空缓冲区成功!\n", process[code].name);
} else if (process[code].currentStep == 3) {
printf("%20s: 该进程被唤醒!申请访问缓冲区成功!\n", process[code].name);
}
} else if (process[code].roleFlag == 0) { //消费者
if (process[code].currentStep == 1) {
process[code].data = pop();
printf("%20s: 该进程被唤醒!申请取产品%d成功!\n", process[code].name, process[code].data);
} else if (process[code].currentStep == 2) {
printf("%20s: 该进程被唤醒!申请访问缓冲区成功!\n", process[code].name);
}
}
process[code].currentStep++;
for (int i = 1; (i <processNum) && (pcq[i] != 0); i++) { //删除队首进程
pcq[i-1] = pcq[i];
if (pcq[i-1] >processNum) {
pcq[i-1] = 0;
}
}
}
void sleep(int pcq[], int code) { //阻塞进程
int i;
process[code-1].currentState = 0; //进程置为阻塞态
for (i = 0; i <processNum; i++) {
if (!pcq[i]) {
pcq[i] = code;
break;
}
}
}
void P(Seamphore *s, Process *p) { //模拟P操作
s->value -= 1;
if (s->value>= 0) {
if (p->roleFlag == 1) { //生产者
if (p->currentStep == 2) {
printf("%20s: 申请空缓冲区成功!\n", p->name);
} else if (p->currentStep == 3) {
printf("%20s: 申请访问缓冲区成功!\n", p->name);
}
} else if (p->roleFlag == 0) { //消费者
if (p->currentStep == 1) {
printf("%20s: 申请取出产品成功!\n", p->name);
} else if (p->currentStep == 2) {
printf("%20s: 申请访问缓冲区成功!\n", p->name);
}
}
p->currentStep++; //下一步
} else if (s->value < 0) {
if (p->roleFlag == 1) { //生产者
if (p->currentStep == 2) {
printf("%20s: 无空缓冲区, 该进程被阻塞!\n", p->name);
} else if (p->currentStep == 3) {
printf("%20s: 其他进程正在访问缓冲区, 该进程被阻塞!\n", p->name);
}
} else if (p->roleFlag == 0) { //消费者
if (p->currentStep == 1) {
printf("%20s: 无产品可取, 该进程被阻塞!\n", p->name);
} else if (p->currentStep == 2) {
printf("%20s: 其他进程正在访问缓冲区, 该进程被阻塞!\n", p->name);
}
}
sleep(s->pcq, p->code); //阻塞进程
}
}
void V(Seamphore *s, Process *p) { //模拟V操作
s->value += 1;
if (p->roleFlag == 1) { //生产者
if (p->currentStep == 5) {
printf("%20s: 释放缓冲区访问权!\n", p->name);
} else if (p->currentStep == 6) {
printf("%20s: 产品已送入缓冲区,产品数量增加!\n", p->name);
}
} else if (p->roleFlag == 0) { //消费者
if (p->currentStep == 4) {
printf("%20s: 释放缓冲区访问权!\n", p->name);
} else if (p->currentStep == 5) {
printf("%20s: 产品已取出,空缓冲区数量增加!\n", p->name);
}
}
if (s->value<= 0) {
wakeup(s->pcq);
}
p->currentStep++;
}
void produce(Process *p) { //模拟生产者进程
switch (p->currentStep) {
case 1: //1 生产产品
p->data = rand()%1000;
printf("%20s: 生产一个产品%d!\n", p->name, p->data);
p->currentStep++;
break;
case 2: //2 申请空缓冲区
P(&empty, p);
break;
case 3: //3 申请访问缓冲区
P(&mutex, p);
break;
case 4: //4 将产品送入缓冲区
push(p->data);
printf("%20s: 将产品%d正送入缓冲区!\n", p->name, p->data);
p->currentStep++;
break;
case 5: //5 释放缓冲区访问权
V(&mutex, p);
break;
case 6: //6 产品已送入缓冲区,产品数量加1
V(&full, p);
p->currentStep = 1;
break;
}
}
void consume(Process *p) { //模拟消费者进程
switch (p->currentStep) {
case 1: //1 申请从缓冲区取出产品
P(&full, p);
break;
case 2: //2 申请访问缓冲区
P(&mutex, p);
break;
case 3: //3 从缓冲区中取出产品
p->data = pop();
printf("%20s: 从缓冲区中正取出产品%d!\n", p->name, p->data);
p->currentStep++;
break;
case 4: //4 释放缓冲区访问权
V(&mutex, p);
break;
case 5: //5 已从缓冲区取出一个产品,空缓冲区数量加1
V(&empty, p);
break;
case 6: //6 消费产品
printf("%20s: 消费产品%d!\n", p->name, p->data);
p->currentStep = 1;
break;
}
}
void rr() { //模拟进程调度
Process *p;
while(1) {
p = &process[rand()%processNum]; //随机选取进程集合内某一进程
if (!p->currentState) { //选取的进程若为阻塞态,重新选取其它可执行进程
continue;
}
if (p->roleFlag) { //1: 生产者 0: 消费者
produce(p);
} else {
consume(p);
}
Sleep(100);
}
}
void deal() {
printf("\t\t生产者消费者算法模拟\n\n");
initProcess();
rr();
}
int main () {
deal();
return 0;
}