操作系统上机5:理发店问题

操作系统 专栏收录该内容
12 篇文章 0 订阅

理发店问题:假设理发店的理发室中有 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_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"
#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;
    //顾客同步信号灯初值设为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);
        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;
    //顾客同步信号灯初值设为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);

    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
    点赞
  • 7
    评论
  • 21
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 精致技术 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值