理发店问题:假设理发店的理发室中有 3 个理发椅子和 3 个理发师,有一个可容 纳4个顾客坐等理发的沙发。此外还有一间等候室,可容纳13位顾客等候进入理发 室。顾客如果发现理发店中顾客已满(超过 20 人),就不进入理发店。 在理发店内,理发师一旦有空就为坐在沙发上等待时间最长的顾客理发,同时 空出的沙发让在等候室中等待时间最长的的顾客就坐。顾客理完发后,可向任何一 位理发师付款。但理发店只有一本现金登记册,在任一时刻只能记录一个顾客的付 款。理发师在没有顾客的时候就坐在理发椅子上睡眠。理发师的时间就用在理发、 收款、睡眠上。


①建立ipc.h 写入代码

#ifndef IPC_H_
// #if IPC
#define IPC_H_#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/msg.h>
#include <unistd.h>
// #include <iostream>#define BUFSZ   256
#define MAXVAL   100
#define STRSIZ   8
#define WRITERQUEST  1 //写请求标识
#define READERQUEST  2 //读请求标识
#define FINISHED  3 //读写完成标识/*信号灯控制用的共同体*/
typedef union semuns {long val;
} Sem_uns;/* 消息结构体*/
typedef struct msgbuf {long mtype;long mid;
} Msg_buf;//信号量
extern key_t costomer_key;
extern int costomer_sem;
extern key_t account_key;
extern int account_sem;extern int sem_val;
extern int sem_flg;//消息队列
extern int wait_quest_flg;
extern key_t wait_quest_key;
extern int wait_quest_id;
extern int wait_respond_flg;
extern key_t wait_respond_key;
extern int wait_respond_id;extern int sofa_quest_flg;
extern key_t sofa_quest_key;
extern int sofa_quest_id;
extern int sofa_respond_flg;
extern key_t sofa_respond_key;
extern int sofa_respond_id;int get_ipc_id(char *proc_file,key_t key);
char *set_shm(key_t shm_key,int shm_num,int shm_flag);
int set_msq(key_t msq_key,int msq_flag);
int set_sem(key_t sem_key,int sem_val,int sem_flag);
int down(int sem_id);
int up(int sem_id);#endif

②建立ipc.c 写入代码

 #include "ipc.h"//信号量
key_t costomer_key;
int costomer_sem;
key_t account_key;
int account_sem;int sem_val;
int sem_flg;//消息队列
int wait_quest_flg;
key_t wait_quest_key;
int wait_quest_id;
int wait_respond_flg;
key_t wait_respond_key;
int wait_respond_id;int sofa_quest_flg;
key_t sofa_quest_key;
int sofa_quest_id;
int sofa_respond_flg;
key_t sofa_respond_key;
int sofa_respond_id;int get_ipc_id(char *proc_file,key_t key) {FILE *pf;int i,j;char line[BUFSZ],colum[BUFSZ];if((pf = fopen(proc_file,"r")) == NULL){perror("Proc file not open");exit(EXIT_FAILURE);}fgets(line, BUFSZ,pf);while(!feof(pf)){i = j = 0;fgets(line, BUFSZ,pf);while(line[i] == ' ') i++;while(line[i] !=' ')colum[j++] = line[i++];colum[j] = '\0';if(atoi(colum) != key)continue;j=0;while(line[i] == ' ')i++;while(line[i] !=' ')colum[j++] = line[i++];colum[j] = '\0';i = atoi(colum);fclose(pf);return i;}fclose(pf);return -1;
}
int down(int sem_id) {struct sembuf buf;buf.sem_op = -1;buf.sem_num = 0;buf.sem_flg = SEM_UNDO;if((semop(sem_id,&buf,1)) <0) {perror("down error ");exit(EXIT_FAILURE);}return EXIT_SUCCESS;
}int up(int sem_id) {struct sembuf buf;buf.sem_op = 1;buf.sem_num = 0;buf.sem_flg = SEM_UNDO;if((semop(sem_id,&buf,1)) <0) {perror("up error ");exit(EXIT_FAILURE);}return EXIT_SUCCESS;
}int set_sem(key_t sem_key,int sem_val,int sem_flg) {int sem_id;  Sem_uns sem_arg;//测试由 sem_key 标识的信号灯数组是否已经建立if((sem_id = get_ipc_id("/proc/sysvipc/sem",sem_key)) < 0 ){//semget 新建一个信号灯,其标号返回到 sem_idif((sem_id = semget(sem_key,1,sem_flg)) < 0){perror("semaphore create error");exit(EXIT_FAILURE);}//设置信号灯的初值sem_arg.val = sem_val;if(semctl(sem_id,0,SETVAL,sem_arg) <0){perror("semaphore set error");exit(EXIT_FAILURE);}}return sem_id;
}char * set_shm(key_t shm_key,int shm_num,int shm_flg) {int i,shm_id;char * shm_buf;//测试由 shm_key 标识的共享内存区是否已经建立if((shm_id = get_ipc_id("/proc/sysvipc/shm",shm_key)) < 0 ){//shmget 新建 一个长度为 shm_num 字节的共享内存,其标号返回到 shm_idif((shm_id = shmget(shm_key,shm_num,shm_flg)) <0){perror("shareMemory set error");exit(EXIT_FAILURE);}//shmat 将由 shm_id 标识的共享内存附加给指针 shm_bufif((shm_buf = (char *)shmat(shm_id,0,0)) < (char *)0){perror("get shareMemory error");exit(EXIT_FAILURE);}for(i=0; i<shm_num; i++) shm_buf[i] = 0;//初始为 0}//shm_key 标识的共享内存区已经建立,将由 shm_id 标识的共享内存附加给指 针 shm_bufif((shm_buf = (char *)shmat(shm_id,0,0)) < (char *)0){perror("get shareMemory error");exit(EXIT_FAILURE);}return shm_buf;
}int set_msq(key_t msq_key,int msq_flg){int msq_id;//测试由 msq_key 标识的消息队列是否已经建立if((msq_id = get_ipc_id("/proc/sysvipc/msg",msq_key)) < 0 ){//msgget 新建一个消息队列,其标号返回到 msq_idif((msq_id = msgget(msq_key,msq_flg)) < 0){perror("messageQueue set error");exit(EXIT_FAILURE);}}return msq_id;
}

③建立Customer.c

#include "ipc.h"
#include<sys/errno.h>int main(int argc,char *argv[])
{int rate;Msg_buf msg_arg;//可在在命令行第一参数指定一个进程睡眠秒数,以调解进程执行速度if(argv[1] != NULL) rate = atoi(argv[1]);else rate = 1;//联系一个请求消息队列wait_quest_flg = IPC_CREAT| 0644;wait_quest_key = 101;wait_quest_id = set_msq(wait_quest_key,wait_quest_flg);//联系一个响应消息队列wait_respond_flg = IPC_CREAT| 0644;wait_respond_key = 102;wait_respond_id = set_msq(wait_respond_key,wait_respond_flg);//联系一个请求消息队列sofa_quest_flg = IPC_CREAT| 0644;sofa_quest_key = 201;sofa_quest_id = set_msq(sofa_quest_key,sofa_quest_flg);//联系一个响应消息队列sofa_respond_flg = IPC_CREAT| 0644;sofa_respond_key = 202;sofa_respond_id = set_msq(sofa_respond_key,sofa_respond_flg);//信号量使用的变量costomer_key = 301;//顾客同步信号灯键值account_key = 302;//账簿互斥信号灯键值sem_flg = IPC_CREAT | 0644;//顾客同步信号灯初值设为0sem_val = 0;//获取顾客同步信号灯,引用标识存 costomer_semcostomer_sem = set_sem(costomer_key,sem_val,sem_flg);//账簿互斥信号灯初值设为 1sem_val = 1;//获取消费者同步信号灯,引用标识存 cons_semaccount_sem = set_sem(account_key,sem_val,sem_flg);int sofa_count=0;int wait_count=0;int i=0;//int count=0;while(1) {sleep(rate);i++;msg_arg.mid = i;if(sofa_count < 4) {if(wait_count != 0) {i--;//阻塞方式接收消息printf("123456\n");msgrcv(wait_quest_id, &msg_arg, sizeof(msg_arg) - sizeof(long), 0, 0);//printf("mid = %d ", msg_arg.mid);msg_arg.mtype=1;int sed = msgsnd(wait_respond_id, &msg_arg,sizeof(msg_arg) - sizeof(long), 0);//printf("sed=%d\n",sed);printf("%ld customer from waiting room to sofa\n", msg_arg.mid);//up(costomer_sem);} else {printf("%d new customer sit sofa\n", i);}sofa_quest_flg=IPC_NOWAIT;msg_arg.mtype=1;if(msgsnd(sofa_quest_id, &msg_arg, sizeof(msg_arg) -sizeof(long), sofa_quest_flg) >= 0){sofa_count++;}else{printf("msgsnd fail\n");// printf("%d\n",msg_arg);// if(errno == EAGAIN){//     printf("errno == EAGAIN\n");// }// else if(errno == EIDRM){//     printf("errno == EIDRM\n");// }// // else if(errno == EACCESS){// //     printf("errno == EACCESS\n");// // }// else if(errno == EFAULT){//     printf("errno == EFAULT\n");// }// else if(errno == EINTR){//     printf("errno == EINTR\n");// }// else if(errno == EINVAL){//     printf("errno == EINVAL\n");// }// msgctl(sofa_quest_id,IPC_RMID,&msg_arg);}} else if(wait_count < 13) {printf("sofa is full %d customer is waiting in the waiting room\n", i);wait_quest_flg = IPC_NOWAIT;msg_arg.mtype=1;msgsnd(wait_quest_id, &msg_arg, sizeof(msg_arg) - sizeof(long), wait_quest_flg);wait_count++;} else {printf("waiting room is full %d customer can't get into barber shop\n", i);//down(costomer_sem);msgrcv(sofa_respond_id, &msg_arg, sizeof(msg_arg) - sizeof(long), 0, 0);sofa_count--;i--;}sofa_quest_flg=IPC_NOWAIT;if(msgrcv(sofa_respond_id, &msg_arg, sizeof(msg_arg)  - sizeof(long), 0, sofa_quest_flg)>=0){sofa_count--;}wait_quest_flg = IPC_NOWAIT;if(msgrcv(wait_respond_id, &msg_arg, sizeof(msg_arg) - sizeof(long), 0, wait_quest_flg)>=0) {wait_count--;}}return 0;
}

④建立Barber.c

#include "ipc.h"int main(int argc,char *argv[])
{//  int i;int rate;Msg_buf msg_arg;//可在在命令行第一参数指定一个进程睡眠秒数,以调解进程执行速度if(argv[1] != NULL) rate = atoi(argv[1]);else rate = 3;//联系一个请求消息队列wait_quest_flg = IPC_CREAT| 0644;wait_quest_key = 101;wait_quest_id = set_msq(wait_quest_key,wait_quest_flg);//联系一个响应消息队列wait_respond_flg = IPC_CREAT| 0644;wait_respond_key = 102;wait_respond_id = set_msq(wait_respond_key,wait_respond_flg);//联系一个请求消息队列sofa_quest_flg = IPC_CREAT| 0644;sofa_quest_key = 201;sofa_quest_id = set_msq(sofa_quest_key,sofa_quest_flg);//联系一个响应消息队列sofa_respond_flg = IPC_CREAT| 0644;sofa_respond_key = 202;sofa_respond_id = set_msq(sofa_respond_key,sofa_respond_flg);//信号量使用的变量costomer_key = 301;//顾客同步信号灯键值account_key = 302;//账簿互斥信号灯键值sem_flg = IPC_CREAT | 0644;//顾客同步信号灯初值设为0sem_val = 0;//获取顾客同步信号灯,引用标识存 costomer_semcostomer_sem = set_sem(costomer_key,sem_val,sem_flg);//账簿互斥信号灯初值设为 1sem_val = 1;//获取消费者同步信号灯,引用标识存 cons_semaccount_sem = set_sem(account_key,sem_val,sem_flg);for(int i=0; i<3;i++){usleep(200000);if(fork()== 0){while (1){wait_quest_flg=IPC_NOWAIT;sleep(rate);if(msgrcv(sofa_quest_id, &msg_arg, sizeof(msg_arg) - sizeof(long), 0, wait_quest_flg)>=0) {//printf("temp %d\n",temp);msg_arg.mtype=1;msgsnd(sofa_respond_id, &msg_arg,sizeof(msg_arg) - sizeof(long), 0);printf("%d barber is serving for %ld customer \n", (int)getpid(), msg_arg.mid);down(account_sem);printf("%d barber is collect %ld customer's money\n", (int)getpid(), msg_arg.mid);up(account_sem);}else {printf("%d barber is sleeping\n", (int)getpid());}}} else{//exit( EXIT_SUCCESS);}}return 0;
}

编译:

gcc -g -c Barber.c ipc.c
gcc Barber.o ipc.o -o barber
gcc -g -c Customer.c ipc.c
gcc Customer.o ipc.o -o customer

运行:

在根目录下打开两个命令窗口,分别执行
./barber
./customer

操作系统上机5:理发店问题相关推荐

  1. 西电操作系统上机实验2

    欢迎各位学弟学妹收藏操作系统上机详解,大家有空也可以看看这篇文章哦--西电计科课程学习 实验2:线程共享进程数据 一.实验目的   1.学习创建线程实现多工作同步运行;   2.了解线程与进程之间的数 ...

  2. 西电操作系统上机实验3

    欢迎各位学弟学妹收藏操作系统上机详解,大家有空也可以看看这篇文章哦--西电计科课程学习 实验3:信号通信 一.实验目的   利用信号通信机制在父子进程及兄弟进程间进行通信. 二.实验内容   父进程创 ...

  3. 操作系统上机考试复习

    操作系统上机考试复习 文件相关 1.打开文件 #include <sys/stat.h> #include <fcntl.h>int open(const char* path ...

  4. 计算机应用能力考试题模拟系统,全国专业技术人员计算机应用能力考试全真模拟考试系统(中文windows_xp操作系统上机模拟考试试题(第2套)...

    全国专业技术人员计算机应用能力考试全真模拟考试系统(中文windows xp操作系统上机模拟考试试题(第二套) 第二套 1.请将系统从管理员用户切换到考试人员用户. 开始菜单--注销--切换用户(从管 ...

  5. 大学操作系统上机实验

      上机实验指导书 课程名称 操作系统 主撰人  刘天波 审核人  栾方军 沈阳建筑大学信息学院 2014 年3月 课程名称:操作系统 上机学时:16 适用专业:计算机科学与技术 先修课程:C语言 一 ...

  6. 西电操作系统上机实验4

    欢迎各位学弟学妹收藏操作系统上机详解,大家有空也可以看看这篇文章哦--西电计科课程学习 实验4:匿名管道通信 一.实验目的   学习使用匿名管道在两个进程间建立通信. 二.实验内容   父进程创建一个 ...

  7. 吉林大学操作系统上机(实验一:Linux进程与线程通讯)

    前言 我希望找到这里的学弟学妹能基于我的内容完成的更好,这里的代码和思路应该是你们的下限!! 我分享这些笔记的初衷是因为我觉得csdn上与之相关的不少博客都收费,但是我当时做的时候,我觉得就那么一点东 ...

  8. 西电操作系统上机实验1

    欢迎各位学弟学妹收藏操作系统上机详解,大家有空也可以看看这篇文章哦--西电计科课程学习. 实验1:创建进程 一.实验目的   学会通过基本的Windows进程控制函数,由父进程创建子进程. 二.实验内 ...

  9. 操作系统上机随笔《实验一》

    OK,今天来写一下这个实验一 1,实验目的 深刻理解线程和进程的概念,掌握线程与进程在组成成分上的差别,以及与其相适应的通讯方式和应用目标. 2,实验内容 以Linux系统进程和线程机制为背景,掌握f ...

最新文章

  1. Spark集群搭建【Spark+Hadoop+Scala+Zookeeper】
  2. OpenCV cv :: UMat与DirectX9曲面的互操作性的实例(附完整代码)
  3. java heap buffer direct buffer_java NIO - DirectBuffer 和 HeapBuffer
  4. C# string转double,double转string
  5. [NOIP2013] 花匠
  6. 机器学习之几个好用的数据下载网站
  7. 笔记.NET基础知识05
  8. 想接私活收入翻倍,建议根据这几个开源SpringBoot项目(含小程序)改改~
  9. 机房收费系统(一)可行性研究报告
  10. e4a 蓝牙温度app_单片机ESP8266无线传输DHT11温湿度(APP+E4A调试说明与程序设计)
  11. MTK 使用iptable 命令来完成网络路由(android WIFI/4G分享网络)
  12. 直播新架构升级:全量支撑淘宝双11直播
  13. Linux学习-96-win和vmware的linux系统之间文件传递
  14. 28 Apr 10:25:21.537 # HandleServiceCommands: system error caught. error code=1072, message = Create
  15. 利用图像内插法放大缩小图像 Matlab
  16. 个人家用nas_个人与家庭NAS怎么样,您知道吗?
  17. 一文弄懂区块链技术原理
  18. Unity3D个人作品展示(Awakening觉醒森林)
  19. android音乐播放器博客,Android版‘音乐一点通’音乐播放器详情
  20. 运维思索:如何纳管服务器实现统一登录

热门文章

  1. 微信公众号获取用户位置定位信息入库asp代码
  2. (转)MTk屏幕切换效果的制作
  3. video的静音,暂停播放
  4. 见到了仰慕已久的李建忠老师
  5. 注意力机制的原理与应用
  6. oracle列转行 多个字段_oracle 行转列~列转行(几种方法)
  7. 经典实用的自动创建Bash脚本文件头的脚本
  8. [脑洞]复杂页面构建方法
  9. 如何判断手机是否支持OTG
  10. 论中国的软件,360和火绒那个更流氓