抽烟者问题。假设一个系统中有三个抽烟者进程,每个抽烟者不断地卷烟并抽烟。抽烟者卷起并抽掉一颗烟需要有三种材料:烟草、纸和胶水。一个抽烟者有烟草,一个有纸,另一个有胶水。系统中还有两个供应者进程,它们无限地供应所有三种材料,但每次仅轮流提供三种材料中的两种。得到缺失的两种材料的抽烟者在卷起并抽掉一颗烟后会发信号通知供应者,让它继续提供另外的两种材料。这一过程重复进行。 请用以上介绍的IPC同步机制编程,实现该问题要求的功能。
二.实验思路:
1.生产者要能提供三种组合的原料:烟草,纸(SP),烟草,胶水(SG),或是纸和胶水(PG),这就需要一个随机数,来决定提供哪种组合的原料。因为需要两个供应者,所以要两个生产者,两个生产者生产的内容一样,决定通过父子进程来实现。因为父子进程同时向一个临界区里写东西,所以加上互斥。并且生产者能发送三种信号来唤醒不同的消费者。
2.需要三个消费者分别消费不同的内容,通过父进程创建两个子进程来实现,父进程和两个子进程分别执行不同的内容,这个和实验一的内容很相似。三个进程在取东西对临界区进行修改的时候要互斥。
3.因为开始时没有资源,所以将唤醒消费者的三个信号的信号量初始值都设为0,因为生产者一次仅供应一个消费者,所以将消费者唤醒生产者的那个信号量初始值设为1。控制互斥的两个信号量pmtx和cmtx都设为1。
代码如下:
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;
typedef struct msgbuf{
long mtype;
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;
//producer semaphore
key_t prod_key;
key_t pmtx_key;
int prod_sem;
int pmtx_sem;
//consumer semaphore
key_t c_PG_key;
key_t c_SG_key;
key_t c_SP_key;
key_t cmtx_key;
int c_PG_sem;
int c_SG_sem;
int c_SP_sem;
int cmtx_sem;
int sem_val;
int sem_flg;
int shm_flg;
#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
producer.c:
#include"ipc.h"
int main(int argc,char*argv[]){
int rate;
if(argv[1]!=NULL) rate=atoi(argv[1]);
else rate=3;
buff_key=101;
buff_num=8;
pput_key=102;
pput_num=1;
shm_flg=IPC_CREAT|0644;
buff_ptr=(char*)set_shm(buff_key,buff_num,shm_flg);
pput_ptr=(int*)set_shm(pput_key,pput_num,shm_flg);
prod_key=201;
pmtx_key=202;
c_PG_key=301;
c_SP_key=302;
c_SG_key=303;
sem_flg=IPC_CREAT|0644;
sem_val=1;
prod_sem=set_sem(prod_key,sem_val,sem_flg);
sem_val=0;
c_PG_sem=set_sem(c_PG_key,sem_val,sem_flg);
c_SG_sem=set_sem(c_SG_key,sem_val,sem_flg);
c_SP_sem=set_sem(c_SP_key,sem_val,sem_flg);
sem_val=1;
pmtx_sem=set_sem(pmtx_key,sem_val,sem_flg);
int pid;
pid=fork();
if(pid==0){
while(1){
int r=rand()%3;
if(r==0){
down(prod_sem);
down(pmtx_sem);
buff_ptr[*pput_ptr+1]='P';
buff_ptr[*pput_ptr+2]='G';
sleep(rate);
printf("%d渚涘簲鍟嗘彁渚涳細绾?c,鑳舵按%c\n",getpid(),buff_ptr[*pput_ptr+1],buff_ptr[*pput_ptr]+2);
up(pmtx_sem);
up(c_PG_sem);}
else if(r==1){
down(prod_sem);
down(pmtx_sem);
buff_ptr[*pput_ptr]='S';
buff_ptr[*pput_ptr+2]='G';
sleep(rate);
printf("%d渚涘簲鍟嗘彁渚涳細鐑?c,鑳舵按%c\n",getpid(),buff_ptr[*pput_ptr],buff_ptr[*pput_ptr]+2);
up(pmtx_sem);
up(c_SG_sem);
}
else if(r==2){
down(prod_sem);
down(pmtx_sem);
buff_ptr[*pput_ptr]='S';
buff_ptr[*pput_ptr+1]='P';
sleep(rate);
printf("%d渚涘簲鍟嗘彁渚涳細鐑?c,绾?c\n",getpid(),buff_ptr[*pput_ptr],buff_ptr[*pput_ptr]+1);
up(pmtx_sem);
up(c_SP_sem);}}
}else{
while(1){
int r=rand()%3;
if(r==0){
down(prod_sem);
down(pmtx_sem);
buff_ptr[*pput_ptr+1]='P';
buff_ptr[*pput_ptr+2]='G';
sleep(rate);
printf("%d渚涘簲鍟嗘彁渚涳細绾?c,鑳舵按%c\n",getpid(),buff_ptr[*pput_ptr+1],buff_ptr[*pput_ptr]+2);
up(pmtx_sem);
up(c_PG_sem);}
else if(r==1){
down(prod_sem);
down(pmtx_sem);
buff_ptr[*pput_ptr]='S';
buff_ptr[*pput_ptr+2]='G';
sleep(rate);
printf("%d渚涘簲鍟嗘彁渚涳細鐑?c,鑳舵按%c\n",getpid(),buff_ptr[*pput_ptr],buff_ptr[*pput_ptr]+2);
up(pmtx_sem);
up(c_SG_sem);
}
else if(r==2){
down(prod_sem);
down(pmtx_sem);
buff_ptr[*pput_ptr]='S';
buff_ptr[*pput_ptr+1]='P';
sleep(rate);
printf("%d渚涘簲鍟嗘彁渚涳細鐑?c,绾?c\n",getpid(),buff_ptr[*pput_ptr],buff_ptr[*pput_ptr]+1);
up(pmtx_sem);
up(c_SP_sem);}}
}
return EXIT_SUCCESS;
}
consumer.c:
#include"ipc.h"
int main(int argc,char*argv[]){
int rate;
if(argv[1]!=NULL) rate=atoi(argv[1]);
else rate=3;
buff_key=101;
buff_num=3;
cget_key=103;
cget_num=1;
shm_flg=IPC_CREAT|0644;
buff_ptr=(char*)set_shm(buff_key,buff_num,shm_flg);
cget_ptr=(int*)set_shm(cget_key,cget_num,shm_flg);
prod_key=201;
pmtx_key=202;
c_PG_key=301;
c_SP_key=302;
c_SG_key=303;
sem_flg=IPC_CREAT|0644;
sem_val=1;
prod_sem=set_sem(prod_key,sem_val,sem_flg);
sem_val=0;
c_PG_sem=set_sem(c_PG_key,sem_val,sem_flg);
c_SG_sem=set_sem(c_SG_key,sem_val,sem_flg);
c_SP_sem=set_sem(c_SP_key,sem_val,sem_flg);
sem_val=1;
cmtx_sem=set_sem(cmtx_key,sem_val,sem_flg);
int pid1,pid2;
if((pid1=fork())==0){
while(1){
down(c_PG_sem);
down(cmtx_sem);
sleep(rate);
printf("%d鏈夌儫鑽夌殑鍚哥儫鑰呬粠渚涘簲鍟嗗緱鍒扮焊%c,鑳舵按%c寮€濮嬪惛鐑焅n",getpid(),buff_ptr[*cget_ptr+1],buff_ptr[*cget_ptr]+2);
up(cmtx_sem);
up(prod_sem);}}
else if((pid2=fork())==0){
while(1){
down(c_SG_sem);
down(cmtx_sem);
sleep(rate);
printf("%d鏈夌焊鐨勫惛鐑熻€呬粠渚涘簲鍟嗗緱鍒扮儫%c,鑳舵按%c寮€濮嬪惛鐑焅n",getpid(),buff_ptr[*cget_ptr],buff_ptr[*cget_ptr]+2);
up(cmtx_sem);
up(prod_sem);}}
else{
while(1){
down(c_SP_sem);
down(cmtx_sem);
sleep(rate);
printf("%d鏈夎兌姘寸殑鍚哥儫鑰呬粠渚涘簲鍟嗗緱鍒扮儫%c,绾?c寮€濮嬪惛鐑焅n",getpid(),buff_ptr[*cget_ptr],buff_ptr[*cget_ptr]+1);
up(cmtx_sem);
up(prod_sem);}}
return EXIT_SUCCESS;
}