操作系统实验3
操作系统实验三
模拟“生产者-消费者”进程实现
include <sys/mman.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#define MAXSEM 5
/*模拟生产者和消费者问题*/
int fullid;
int emptyid;
int mutxid;
void main()
{
struct sembuf P, V;//声明两个结构体P、V
union semun
{
int val;
struct semid_ds *buf;
ushort *array;
} arg;
/*声明四个共享主存*/
int *array;//定义数组表示缓冲池
int *sum;
int *set;
int *get;
/*mmap:把文件内容映射到内存中,实现共享*/
array = (int *)mmap(NULL, sizeof(int) * 5, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); //sizeof(int)*5,开辟一个能放5个的内存空间共享
sum = (int *)mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
get = (int *)mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
set = (int *)mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
*sum = 0;
*get = 0;
*set = 0;
/*semget:创建一个信号量集合或获取一个已经存在的信号量集*/
fullid = semget(IPC_PRIVATE, 1, IPC_CREAT | 00666); //创建三个信号量集,信号量集中各有三个信号量,所有人都可以访问
emptyid = semget(IPC_PRIVATE, 1, IPC_CREAT | 00666);
mutxid = semget(IPC_PRIVATE, 1, IPC_CREAT | 00666);
/*semctl:赋初值,对信号量进行一系列控制*/
arg.val = 0;
if (semctl(fullid, 0, SETVAL, arg) == -1)//对fullid赋初值为0
perror("semctl semval error");
arg.val = MAXSEM;
if (semctl(emptyid, 0, SETVAL, arg) == -1)//对emptyid赋初值为maxsem
perror("semctl semval error");
arg.val = 1;
if (semctl(mutxid, 0, SETVAL, arg) == -1)//对互斥信号量赋初值1
perror("semctl semval error");
V.sem_num = 0;//对具体的信号量的操作
V.sem_op = 1;
V.sem_flg = SEM_UNDO;
P.sem_num = 0;
P.sem_op = -1;
P.sem_flg = SEM_UNDO;
if (fork() == 0)//一个子进程充当生产者进程
{
while (*set < 20)
{
/*semop:对信号量仅从P、V操作,参数为信号量集标识符,sops,nsops*/
semop(emptyid, &P, 1); //同步P操作
semop(mutxid, &P, 1); //互斥P操作
array[(*set) % MAXSEM] = *set + 1;//生产了一个,向缓冲池中放
printf("Producer %d\n", array[(*set) % MAXSEM]);//生产产品的标号+1
(*set)++; //指针下移
semop(mutxid, &V, 1); //互斥V操作
semop(fullid, &V, 1); //同步V操作
}
sleep(2);//休眠两秒
printf("Producer is over\n");
exit(0);
}
else
{
if (fork() == 0)//一个子进程充当消费者进程
{
while (1)
{
semop(fullid, &P, 1); //同步P操作
semop(mutxid, &P, 1);//互斥P操作
if (*get < 20){//判断是否所有产品都被消费了
*sum += array[(*get) % MAXSEM];
printf("The consumerA Get Number %d\n", array[(*get) % MAXSEM]);//消费者A取了多少个
(*get)++;//指针下移
if (*get == 20){//判断此次消费是不是最后一次消费
printf("The sum is %d\n", *sum);
}
}
semop(mutxid, &V, 1); //互斥V操作
semop(emptyid, &V, 1); //同步V操作
if (*get == 20)
{
break;
}
}
printf("ConsumerA is over\n");
exit(0);
}
else
{
if (fork() == 0)//另一个子进程充当消费者进程,两个消费者不能同时向外取
{
while (1)//和上面同理
{
semop(fullid, &P, 1);
semop(mutxid, &P, 1);
if (*get < 20){
*sum += array[(*get) % MAXSEM];
printf("The consumerB Get Number %d\n", array[(*get) % MAXSEM]);
(*get)++;
if (*get == 20){
printf("The sum is %d\n", *sum);
}
}
semop(mutxid, &V, 1);
semop(emptyid, &V, 1);
if (*get == 20){
break;
}
}
printf("ConsumerB is over\n");
exit(0);
}
else{
sleep(3);
exit(0);
}
}
}
}
/*fork()>0 父进程 fork()=0 子进程
运行后截图:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人