在进行这个实验的时候,写完代码开始运行第一次之后,再次运行应该删除之前创建的消息队列,否则会导致奇怪的错误。也就是之前的消息还未读完,进程发生错乱。
删除消息队列使用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
得到实验结果: