操作系统实验五

实验内容:

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

二.实验思路:

1.因为有三个理发师和三把理发椅,理发师和理发椅是一一对应的,所以可以忽略理发椅而直接将它和理发师视为一体,因为三个理发师进行的是同样的动作——理发、睡眠和收款,所以需要利用fork()调用建立两个子进程,和父进程一起用来分别代表三个理发师。

2.因为开始没顾客,所以理发师一开始都直接进入休眠状态。

3. 因为理发店只有一本现金登记册,在任一时刻只能记录一个顾客的付款,所以应设一个互斥信号量account_sem用来控制理发师对登记册的修改访问。

4.因为沙发只有4个,等候室只能有13个人呆在里面,所以要设两个数sofa_count和wait_count,用来记录当前在沙发上和在等候室里的人数,以分别控制人数不超过要求。并且为防止多个进程同时对这两个数进行修改造成混乱,应设置一个互斥信号量count_sem 用来控制进程对这两个数的修改。

5.建立四个 消息队列sofa_quest_flg,sofa_respond_flg和

wait_quest_flg,wait_respond_flg;sofa_quest_flg用来记录当前请求剪发的消息,相当于摆在医生桌面上的病例,理发师通过检查该消息队列来判断有没有顾客等待理发,若没有则睡眠。sofa_respond_flg用来记录理发师完成剪发的消息。Wait_quest_flg用来记录请求沙发座位的消息,wait_respond_flg用来记录请求到沙发座位的消息。如果理发师空闲,则检查sofa_quest_flg看有没有顾客等待理发,如果沙发当前没有坐满则看等候室里是否有人,有人则检查wait_quest_flg队列来选取等候最久的人坐到沙发上。检查sofa_respond_flg队列,如果里面有消息,则说明有顾客完成理发,则把沙发当前的人数sofa_count减一;检查wait_respond_flg,如果里面有消息,则说明有顾客从等候室进入沙发,则把等候室当前的人数wait_count减一。

三.实验结果:


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>

#define BUFSZ 256
#define WRITERQUEST 1
#define READERQUEST 2
#define FINISHED 3

typedef union semuns{
	int val;
}Sem_uns;

typedef struct msgbuf{
	long mtype;
	int mid;
}Msg_buf;
key_t account_key;
int account_sem;

key_t count_key;
int count_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);
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);

ipc.c:
#include"ipc.h"
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;
if((sem_id=get_ipc_id("/proc/sysvipc/sem",sem_key))<0)
{
if((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;
if((shm_id=get_ipc_id("/proc/sysvipc/shm",shm_key))<0){
if((shm_id=shmget(shm_key,shm_num,shm_flg))<0)
{
perror("share memory set error");
exit(EXIT_FAILURE);
}
if((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;
}
if((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;
if((msq_id=get_ipc_id("/proc/sysvipc/msg",msq_key))<0){
if((msq_id=msgget(msq_key,msq_flg))<0){
perror("messageQueue set error");
exit(EXIT_FAILURE);
}
}
return msq_id;}

barber.c:
#include"ipc.h"
int main(int argc,char*argv[]){
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);
account_key=301;
count_key=302;
sem_flg=IPC_CREAT|0644;
sem_val=1;
account_sem=set_sem(account_key,sem_val,sem_flg);
sem_val=1;
count_sem=set_sem(count_key,sem_val,sem_flg);
int pid1,pid2;
if((pid1=fork())==0){
while(1){
printf("%d号理发师睡眠\n",getpid());
if(msgrcv(sofa_quest_id,&msg_arg,sizeof(msg_arg),0,0)>=0){
msgsnd(sofa_respond_id,&msg_arg,sizeof(msg_arg),0);
printf("%d号理发师为%d号顾客理发\n",getpid(),msg_arg.mid);
sleep(rate);
down(account_sem);
printf("%d号理发师为%d号顾客收款\n",getpid(),msg_arg.mid);
up(account_sem);
}
}
}else if((pid2=fork())==0){
while(1){
printf("%d号理发师睡眠\n",getpid());
if(msgrcv(sofa_quest_id,&msg_arg,sizeof(msg_arg),0,0)>=0){
msgsnd(sofa_respond_id,&msg_arg,sizeof(msg_arg),0);
printf("%d号理发师为%d号顾客理发\n",getpid(),msg_arg.mid);
sleep(rate);
down(account_sem);
printf("%d号理发师为%d号顾客收款\n",getpid(),msg_arg.mid);
up(account_sem);
}
}
}else{
while(1){
printf("%d号理发师睡眠\n",getpid());
if(msgrcv(sofa_quest_id,&msg_arg,sizeof(msg_arg),0,0)>=0){
msgsnd(sofa_respond_id,&msg_arg,sizeof(msg_arg),0);
printf("%d号理发师为%d号顾客理发\n",getpid(),msg_arg.mid);
sleep(rate);
down(account_sem);
printf("%d号理发师为%d号顾客收款\n",getpid(),msg_arg.mid);
up(account_sem);
}
}
}
return EXIT_SUCCESS;
}

Customer.c:
#include"ipc.h"
int main(int argc,char* argv[])
{
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);
account_key=301;
count_key=302;
sem_flg=IPC_CREAT|0644;
sem_val=1;
account_sem=set_sem(account_key,sem_val,sem_flg);
sem_val=1;
count_sem=set_sem(count_key,sem_val,sem_flg);
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);
account_key=301;
count_key=302;
sem_flg=IPC_CREAT|0644;
sem_val=1;
account_sem=set_sem(account_key,sem_val,sem_flg);
sem_val=1;
count_sem=set_sem(count_key,sem_val,sem_flg);
int wait_count=0;
int sofa_count=0;
int i=0;
while(1){
sleep(rate);
down(count_sem);
i++;
up(count_sem);
msg_arg.mid=i;
if(sofa_count>=0){
msgsnd(sofa_quest_id,&msg_arg,sizeof(msg_arg),0)
}
if(sofa_count<4){
if(wait_count!=0){
msgrcv(wait_quest_id,&msg_arg,sizeof(msg_arg),0,0);
msgsnd(wait_respond_id,&msg_arg,sizeof(msg_arg),0);
printf("%d号顾客从等候室坐到沙发上\n",msg_arg.mid);
}
else{
printf("%d号顾客从外面进来坐到沙发上\n",msg_arg.mid);
}
down(count_sem);
sofa_count++;
up(count_sem);
}
else if(wait_count<13){
printf("沙发已满,%d号顾客进入等候室等待\n",msg_arg.mid);
msgsnd(wait_quest_id,&msg_arg,sizeof(msg_arg),0);
down(count_sem);
wait_count++;
up(count_sem);
}
else{
printf("理发店已满%d号顾客没有进入理发店\n",msg_arg.mid);
}
wait_respond_flg=IPC_NOWAIT;
if(msgrcv(wait_respond_id,&msg_arg,sizeof(msg_arg),0,wait_respond_flg)>=0){
down(count_sem);
wait_count--;
up(count_sem);
}
sofa_respond_flg=IPC_NOWAIT;
if(msgrcv(sofa_respond_id,&msg_arg,sizeof(msg_arg),0,sofa_respond_flg)>=0){
down(count_sem);
sofa_count--;
up(count_sem);
}
}
return EXIT_SUCCESS;
}


  • 2
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值