操作系统实验五、进程互斥实验——理发店问题

问题描述

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

程序实现

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 MAXVAL 100
#define STRSIZ 8
#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 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);
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;
//测试由 sem_key 标识的信号灯数组是否已经建立
if((sem_id = get_ipc_id("/proc/sysvipc/sem",sem_key)) < 0 ){
//semget 新建一个信号灯,其标号返回到 sem_id
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;
//测试由 shm_key 标识的共享内存区是否已经建立
if((shm_id = get_ipc_id("/proc/sysvipc/shm",shm_key)) < 0 ){
//shmget 新建 一个长度为 shm_num 字节的共享内存,其标号返回到 shm_id
if((shm_id = shmget(shm_key,shm_num,shm_flg)) <0){
perror("shareMemory set error");
exit(EXIT_FAILURE);
}
//shmat 将由 shm_id 标识的共享内存附加给指针 shm_buf
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;
//初始为 0
}
//shm_key 标识的共享内存区已经建立,将由 shm_id 标识的共享内存附加给指 针
shm_buf
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;
//测试由 msq_key 标识的消息队列是否已经建立
if((msq_id = get_ipc_id("/proc/sysvipc/msg",msq_key)) < 0 ){
//msgget 新建一个消息队列,其标号返回到 msq_id
if((msq_id = msgget(msq_key,msq_flg)) < 0){
perror("messageQueue set error");
exit(EXIT_FAILURE);
}
}
return msq_id;
}

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);
//信号量使用的变量
costomer_key = 301;//顾客同步信号灯键值
account_key = 302;//账簿互斥信号灯键值
sem_flg = IPC_CREAT | 0644;
//顾客同步信号灯初值设为 0
sem_val = 0;
//获取顾客同步信号灯,引用标识存 costomer_sem
costomer_sem = set_sem(costomer_key,sem_val,sem_flg);
//账簿互斥信号灯初值设为 1
sem_val = 1;
//获取消费者同步信号灯,引用标识存 cons_sem
account_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);
// count++;
// printf("count = %d ", count);
i++;
// printf("i = %d ", i);
msg_arg.mid = i;
if(sofa_count < 4) {
if(wait_count != 0) {
i--;
//阻塞方式接收消息
msgrcv(wait_quest_id, &msg_arg, sizeof(msg_arg), 0, 0);
printf("mid = %d ", msg_arg.mid);
msgsnd(wait_respond_id, &msg_arg,sizeof(msg_arg), 0);
printf("%d 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;
if(msgsnd(sofa_quest_id, &msg_arg, sizeof(msg_arg), sofa_quest_flg) >= 0){
// sofa_count++;
// return 0;
}
sofa_count++;
} else if(wait_count < 13) {
printf("sofa is full %d customer is waiting in the waiting room\n", i);
wait_quest_flg = IPC_NOWAIT;
msgsnd(wait_quest_id, &msg_arg, sizeof(msg_arg), 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), 0, 0);
sofa_count--;
i--;
}
sofa_quest_flg=IPC_NOWAIT;
if(msgrcv(sofa_respond_id, &msg_arg, sizeof(msg_arg), 0, sofa_quest_flg)>=0){
sofa_count--;
}
wait_quest_flg = IPC_NOWAIT;
if(msgrcv(wait_respond_id, &msg_arg, sizeof(msg_arg), 0, wait_quest_flg)>=0) {
wait_count--;
}
}
return 0;
}

barbaer.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;
//顾客同步信号灯初值设为 0
sem_val = 0;
//获取顾客同步信号灯,引用标识存 costomer_sem
costomer_sem = set_sem(costomer_key,sem_val,sem_flg);
//账簿互斥信号灯初值设为 1
sem_val = 1;
//获取消费者同步信号灯,引用标识存 cons_sem
account_sem = set_sem(account_key,sem_val,sem_flg);
int pid1, pid2;
pid1=fork();
if(pid1==0) {
while(1) {
// wait_quest_flg=IPC_NOWAIT;
//printf("%d barber is sleeping \n", getpid());
wait_quest_flg=IPC_NOWAIT;
sleep(rate);
if(msgrcv(sofa_quest_id, &msg_arg, sizeof(msg_arg), 0, wait_quest_flg)>=0) {
//printf("temp %d\n",temp);
msgsnd(sofa_respond_id, &msg_arg,sizeof(msg_arg), 0);
printf("%d barber is serving for %d customer \n", getpid(), msg_arg.mid);
down(account_sem);
printf("%d barber is collect %d customer's money\n", getpid(), msg_arg.mid);
up(account_sem);
}else {
printf("%d barber is sleeping\n", getpid());
}
}
} else {
pid2=fork();
if(pid2==0) {
while(1) {
// wait_quest_flg=IPC_NOWAIT;
//printf("%d barber is sleeping\n", getpid());
wait_quest_flg=IPC_NOWAIT;
sleep(rate);
if(msgrcv(sofa_quest_id, &msg_arg, sizeof(msg_arg), 0, wait_quest_flg)>=0) {
msgsnd(sofa_respond_id, &msg_arg,sizeof(msg_arg), 0);
printf("%d barber is serving for %d customer \n", getpid(), msg_arg.mid);
down(account_sem);
printf("%d barber is collect %d customer's money\n", getpid(),
msg_arg.mid);
up(account_sem);
} else {
printf("%d barber is sleeping\n", getpid());
}
}
} else {
while(1) {
// wait_quest_flg=IPC_NOWAIT;
//printf("%d barber is sleeping\n", getpid());
wait_quest_flg=IPC_NOWAIT;
sleep(rate);
if(msgrcv(sofa_quest_id, &msg_arg, sizeof(msg_arg), 0, wait_quest_flg)>=0) {
msgsnd(sofa_respond_id, &msg_arg,sizeof(msg_arg), 0);
printf("%d barber is serving for %d customer \n", getpid(), msg_arg.mid);
down(account_sem);
printf("%d barber is collect %d customer's money\n", getpid(),
msg_arg.mid);
up(account_sem);
} else {
printf("%d barber is sleeping\n", getpid());
}
}
}
}
return 0;
}

运行
在这里插入图片描述在这里插入图片描述

发布了37 篇原创文章 · 获赞 1511 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/weixin_43943977/article/details/101864948