/*抽烟者问题。假设一个系统中有三个抽烟者进程,每个抽烟者不断地卷烟并抽
烟。抽烟者卷起并抽掉一颗烟需要有三种材料:烟草、纸和胶水。一个抽烟者有烟
草,一个有纸,另一个有胶水。系统中还有两个供应者进程,它们无限地供应所有
三种材料,但每次仅轮流提供三种材料中的两种。得到缺失的两种材料的抽烟者在
卷起并抽掉一颗烟后会发信号通知供应者,让它继续提供另外的两种材料。这一过
程重复进行。请用以上介绍的IPC 同步机制编程,实现该问题要求的功能。*/
//ipc.h
#include
#include
#include
#include
#include
#include
#include
#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;
struct msgbuf {
long mtype;
int mtext[1];
}msg_buf;
key_t smoker_key;
int smoker_sem;
key_t supp_key;
int supp_sem;
key_t msg_key;
int msg_id;
int sem_val;
int sem_flg;
//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\n");
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\n");
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);
}
if(semctl(sem_id,0,SETVAL,sem_arg) <0){
perror("semaphore set error");
exit(EXIT_FAILURE);
}
}
return sem_id;
}
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;
}
//smoker.c
#include "ipc.h"
int main(int argc,char * argv[]){
int rate=3;
if(argv[1]!=NULL){
rate=atoi(argv[1]);
}
smoker_key=101;
supp_key=201;
msg_key=301;
sem_flg=IPC_CREAT|0644;
sem_val=3;
smoker_sem=set_sem(smoker_key,sem_val,sem_flg);
sem_val=2;
supp_sem=set_sem(supp_key,sem_val,sem_flg);
msg_id=set_msq(msg_key,sem_flg);
while(1){
down(supp_sem);
msg_buf.mtype=3;
msg_buf.mtext[0]=getpid();
msgsnd(msg_id,&msg_buf,1,0);
printf("Smoker %d just sent a request to the supply.\n",getpid());
sleep(rate);
msg_buf.mtype=2;
msgrcv(msg_id,&msg_buf,1,2,0);
printf("Smoker got ingredient from the supply %d.\n",msg_buf.mtext[0]);
printf("Smoker %d just finished smoking.\n",getpid());
up(smoker_sem);
}
return EXIT_SUCCESS;
}
//supply.c
#include "ipc.h"
int main(int argc,char *argv[]){
int rate=3;
if(argv[1]!=NULL){
rate=atoi(argv[1]);
}
smoker_key=101;
supp_key=201;
msg_key=301;
sem_flg=IPC_CREAT|0644;
sem_val=3;
smoker_sem=set_sem(smoker_key,sem_val,sem_flg);
sem_val=2;
supp_sem=set_sem(supp_key,sem_val,sem_flg);
msg_id=set_msq(msg_key,sem_flg);
pid_t smk_pid;
while(1){
msg_buf.mtype=3;
msgrcv(msg_id,&msg_buf,1,3,0);
smk_pid=msg_buf.mtext[0];
printf("Supply %d just got a request from Smoker %d.\n",getpid(),smk_pid);
down(smoker_sem);
sleep(rate);
msg_buf.mtype=2;
msg_buf.mtext[0]=getpid();
msgsnd(msg_id,&msg_buf,1,0);
printf("Ingredient was sent from Supply %d to Smoker %d.\n",getpid(),smk_pid);
up(supp_sem);
}
return EXIT_SUCCESS;
}
//removeipc.c
//删除已建立的消息队列和信号量。
#include "ipc.h"
int main(){
smoker_key=101;
supp_key=201;
msg_key=301;
int id;
Sem_uns sem_arg;
if((id=get_ipc_id("/proc/sysvipc/sem",supp_key))>=0){
semctl(id,0,IPC_RMID,sem_arg);
}
if((id=get_ipc_id("/proc/sysvipc/sem",smoker_key))>=0){
semctl(id,0,IPC_RMID,sem_arg);
}
if((id=get_ipc_id("/proc/sysvipc/msg",msg_key))>=0){
msgctl(id,IPC_RMID,NULL);
}
return 0;
}
//Makefile
head = ipc.h
sup_srcs = supply.c ipc.c
sup_objs = supply.o ipc.o
smk_srcs = smoker.c ipc.c
smk_objs = smoker.o ipc.o
rm_srcs = removeipc.c ipc.c
rm_objs = removeipc.o ipc.o
opts = -g -c
all: supply smoker removeipc
smoker: $(smk_objs)
gcc $(smk_objs) -o smoker
supply: $(sup_objs)
gcc $(sup_objs) -o supply
removeipc: $(rm_objs)
gcc $(rm_objs) -o removeipc
removeipc.o: $(rm_srcs)
gcc $(opts) $(rm_srcs)
smoker.o: $(smk_srcs)
gcc $(opts) $(smk_srcs)
supply.o: $(sup_srcs)
gcc $(opts) $(sup_srcs)
clean:
rm *.o supply smoker