操作系统实验5-理发师问题-进程的同步与互斥

在进行这个实验的时候,写完代码开始运行第一次之后,再次运行应该删除之前创建的消息队列,否则会导致奇怪的错误。也就是之前的消息还未读完,进程发生错乱。
删除消息队列使用ipcrm命令,使用前应用ipcrm --help查看。
理发师算法:利用 fork()开两个子进程,和主进程一起,分别代表 barber1 2 3; Barber:每次从 sofa 队列里抓一个人起来理发。如果队列里没人,那么阻塞。 利用 msgrcv()实现。抓完人后利用 msgsnd()回应,在 sofa_repond 的消息队列里增加 一个消息。 Consumer:如果 sofa_quest 队列里少于四个人,则检查等候室,如果 wait_quest 队列里有 人就坐到沙发上去,同时发送 wait_respond 到 wait_respond 队列里。如果等候室里没人就 直接坐到沙发上去。然后向 sofa_quest 队列里多增加一个消息。 如果 sofa 满了,就进等候室,向等候室队列里加一个消息。 都满了就走人。然后接受来自 respond 队列的消息,如果沙发和等候室对应的 respond 队列 里有消息,就取一个消息,相应的人数 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>
#include <unistd.h>
#include<signal.h>
#define BUFSZ 256 
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);
typedef union semuns {
 int val;
} Sem_uns; 
typedef struct msgbuf {
 long mtype;
 int mid;
// char mtext[1];
} Msg_buf; 
key_t buff_key;
int buff_num;
char *buff_ptr;
key_t pput_key;
int pput_num;
int *pput_ptr;
key_t cget_key;
int cget_num;
int *cget_ptr;
key_t prod_key; 
key_t pmtx_key;
int prod_sem;
int pmtx_sem;
key_t cons_key; 
key_t cmtx_key;
int cons_sem;
int cmtx_sem;
int sem_val;
int sem_flg;
int shm_flg;
//message queue
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; 
key_t customer_key;
int customer_sem;
key_t account_key;
int account_sem;

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("shareMemory 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; //��ʼΪ 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 )
    {
        printf("a new messge queue was build!\n");
        if((msq_id = msgget(msq_key,msq_flg)) < 0)
        {
            perror("messageQueue set error");
            exit(EXIT_FAILURE);
        }
    }
    return msq_id;
}

producer.c

#include "ipc.h"
int main(int argc,char *argv[]){
    int rate;
    if(argv[1]!=NULL) rate = atoi(argv[1]);
    else rate = 1;
    Msg_buf msg_arg;
    wait_quest_flg=IPC_CREAT|0644;
    wait_quest_key = 111;
    wait_quest_id = set_msq(wait_quest_key,wait_quest_flg);
    wait_respond_flg=IPC_CREAT|0644;
    wait_respond_key=112;
    wait_respond_id=set_msq(wait_respond_key,wait_respond_flg);
    sofa_quest_flg=IPC_CREAT|0644;
    sofa_quest_key = 211;
    sofa_quest_id = set_msq(sofa_quest_key,sofa_quest_flg);
    sofa_respond_flg=IPC_CREAT|0644;
    sofa_respond_key=212;
    sofa_respond_id=set_msq(sofa_respond_key,sofa_respond_flg);
    customer_key=311;
    sem_flg=IPC_CREAT|0644;
    sem_val=0;
    customer_sem=set_sem(customer_key,sem_val,sem_flg);
    account_key=312;
    sem_flg=IPC_CREAT|0644;
    sem_val=1;
    account_sem=set_sem(account_key,sem_val,sem_flg);
    int pid1,pid2;
    pid1=fork();
    if(pid1==0){
        while(1){
            printf("barber 1 is sleeping\n");
            sofa_quest_flg=0;
            if(msgrcv(sofa_quest_id,&msg_arg,sizeof(msg_arg),0,sofa_quest_flg)>=0){
                //quest for sofa message queue
                msgsnd(sofa_respond_id,&msg_arg,sizeof(msg_arg),0);
                printf("barber 1 is serving for customer %d\n",msg_arg.mid);
                sleep(rate);
                down(account_sem);
                printf("barber 1 is charging customer %d\n",msg_arg.mid);
                up(account_sem);
            }else{
                printf("barber 1 is sleeping\n");
            }
        }
    }
    else{
        pid2=fork();
        if(pid2==0){
            while(1){
                printf("barber 2 is sleeping\n");
                sofa_quest_flg=0;
                if(msgrcv(sofa_quest_id,&msg_arg,sizeof(msg_arg),0,sofa_quest_flg)>=0){
                //quest for sofa message queue
                msgsnd(sofa_respond_id,&msg_arg,sizeof(msg_arg),0);
                printf("barber 2 is serving for customer %d\n",msg_arg.mid);
                sleep(rate);
                down(account_sem);
                printf("barber 2 is charging customer %d\n",msg_arg.mid);
                up(account_sem);
                }else{
                    printf("barber 2 is sleeping\n");
                }
            }
        }
        else{
            while(1){
                printf("barber 3 is sleeping\n");
                sofa_quest_flg=0;
                if(msgrcv(sofa_quest_id,&msg_arg,sizeof(msg_arg),0,sofa_quest_flg)>=0){
                //quest for sofa message queue
                msgsnd(sofa_respond_id,&msg_arg,sizeof(msg_arg),0);
                printf("barber 3 is serving for customer %d\n",msg_arg.mid);
                sleep(rate);
                down(account_sem);
                printf("barber 3 is charging customer %d\n",msg_arg.mid);
                up(account_sem);
                }else{
                    printf("barber 3 is sleeping\n");
                }
            }
        }
    }
    return EXIT_SUCCESS;
}

consumer.c

#include "ipc.h"
//typedef void(*sighandler_t)(int);
int main(int argc,char *argv[]){
    int rate;
    if(argv[1]!=NULL) rate = atoi(argv[1]);
    else rate = 1;
    Msg_buf msg_arg;
    wait_quest_flg=IPC_CREAT|0644;
    wait_quest_key = 111;
    wait_quest_id = set_msq(wait_quest_key,wait_quest_flg);
    wait_respond_flg=IPC_CREAT|0644;
    wait_respond_key=112;
    wait_respond_id=set_msq(wait_respond_key,wait_respond_flg);
    sofa_quest_flg=IPC_CREAT|0644;
    sofa_quest_key = 211;
    sofa_quest_id = set_msq(sofa_quest_key,sofa_quest_flg);
    sofa_respond_flg=IPC_CREAT|0644;
    sofa_respond_key=212;
    sofa_respond_id=set_msq(sofa_respond_key,sofa_respond_flg);
    customer_key=311;
    sem_flg=IPC_CREAT|0644;
    sem_val=0;
    customer_sem=set_sem(customer_key,sem_val,sem_flg);
    account_key=312;
    sem_flg=IPC_CREAT|0644;
    sem_val=1;
    account_sem=set_sem(account_key,sem_val,sem_flg);
    int sofa_count=0;
    int wait_count=0;
    int id=0;
    while(1){
        sleep(rate);
        //signal(SIGINT,(sighandler_t)pause);
        id++;
        msg_arg.mid=id;
        if(sofa_count<4){
            if(wait_count!=0)
            {
                wait_quest_flg=IPC_NOWAIT;
                msgrcv(wait_quest_id,&msg_arg,sizeof(msg_arg),0,wait_quest_flg);
                msgsnd(wait_respond_id,&msg_arg,sizeof(msg_arg),0);
                printf("customer %d move to the sofa from waiting room\n",id);
                sofa_count++;
               // wait_count--;
            }
            else{
                printf("a new customer %d sit at sofa\n",id);
                sofa_count++;
            }
            sofa_quest_flg=IPC_NOWAIT;
            if(msgsnd(sofa_quest_id,&msg_arg,sizeof(msg_arg),sofa_quest_flg)>=0){
                //sofa_count++;       
            }
        }
        else if(wait_count<13){
            printf("sofa is full,customer %d is waiting in waiting room\n",id);
            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, customer %d leaves\n",id);
        }
        sofa_respond_flg=IPC_NOWAIT;
        if(msgrcv(sofa_respond_id,&msg_arg,sizeof(msg_arg),0,sofa_respond_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 EXIT_SUCCESS;
}

编写makefile

hdrs = ipc.h
opts = -g -c
c_src = consumer.c ipc.c 
c_obj = consumer.o ipc.o
p_src = producer.c ipc.c 
p_obj = producer.o ipc.o
all:   producer consumer
consumer:  $(c_obj)
  gcc $(c_obj) -o consumer 
consumer.o:  $(c_src) $(hdrs)
  gcc $(opts) $(c_src) 
producer:  $(p_obj)
  gcc $(p_obj) -o producer 
producer.o:  $(p_src) $(hdrs)
  gcc $(opts) $(p_src) 
clean:
  rm consumer producer *.o

make

打开两个终端,一个运行./producer 一个运行./consumer
得到实验结果:

在这里插入图片描述

  • 2
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
生产者-消费者问题是指在一个共享缓冲区中,生产者进程向缓冲区中放入数据,而消费者进程从缓冲区中取出数据。为了避免生产者进程在缓冲区已满时继续放入数据,或者消费者进程在缓冲区为空时继续取出数据,需要进行进程同步互斥。 一种解决方案是使用信号量。定义两个信号量:empty和full,分别表示缓冲区空闲的空间和缓冲区已经存储的数据量。当生产者进程向缓冲区中放入数据时,需要先判断empty信号量的值是否大于0,如果是,则表示缓冲区还有空闲的空间,可以放入数据;否则,需要等待消费者进程取出数据,释放空间。当消费者进程从缓冲区中取出数据时,需要先判断full信号量的值是否大于0,如果是,则表示缓冲区中有数据可以取出;否则,需要等待生产者进程放入数据,增加数据量。 下面是一个Python实现的生产者-消费者问题的例子: ```python import threading import time # 定义缓冲区大小 BUFFER_SIZE = 10 # 定义信号量 empty = threading.Semaphore(BUFFER_SIZE) full = threading.Semaphore(0) # 定义缓冲区 buffer = [] # 定义生产者线程 class ProducerThread(threading.Thread): def run(self): global buffer while True: # 生产数据 item = time.time() # 获取empty信号量 empty.acquire() # 向缓冲区中放入数据 buffer.append(item) print("Produced:", item) # 释放full信号量 full.release() # 等待一段时间 time.sleep(1) # 定义消费者线程 class ConsumerThread(threading.Thread): def run(self): global buffer while True: # 获取full信号量 full.acquire() # 从缓冲区中取出数据 item = buffer.pop(0) print("Consumed:", item) # 释放empty信号量 empty.release() # 等待一段时间 time.sleep(2) # 创建生产者线程和消费者线程 producer_thread = ProducerThread() consumer_thread = ConsumerThread() # 启动线程 producer_thread.start() consumer_thread.start() ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值