📄 barber_ok.c
字号:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <stdio.h>
#include <unistd.h>
#define DEFAULT_N (15+3) /*没有参数时,缺省为15个顾客和3个理发师*/
/*宏定义wait和signal*/
#define SIGNAL(A,B) V.sem_num = (A+B);if(semop(semid,&V,1)==-1) { perror("signal fail");exit(1);}
#define WAIT(A,B) P.sem_num = (A+B);if(semop(semid,&P,1)==-1) { perror("wait fail");exit(1);}
union semun
{
int val;/*for SETVAL*/
struct semid_ds *buf;/*for IPC_STAT and IPC_SET*/
ushort *array;/*for GETALL and SETALL*/
};
enum
{
MAX_CAPACITY=0,
SOFA,
BARBER_CHAIR,
CASHIER=5,
MUTEX,
CUST_READY=7,
LEAVE_B_CHAIR=10,
PAYMENT=13,
RECEIPT=16,
FINISHED=19,
queueLOCK=22
};
static struct sembuf P = {0,-1,SEM_UNDO},V = {0,1,SEM_UNDO};
/******wait和signal操作******/
static ushort start_val[23] = {20,4,1,1,1,1,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
/******23个信号量的初值******/
static int semid,shmid;/*信号量ID和共享内存ID*/
struct QueueType
{
int value[4];
int out;
int in;
};
void enqueue(struct QueueType* q,int val )/*入队列*/
{
if((q->in+1)%4==q->out)
{
printf("queue is full\n");
return;
}
else
{
q->value[q->in] = val;
q->in = (q->in+1)%4;
printf("Barber %d(his pid is %d) is ready ,he wants to send No.%d to a customer\n",val,getpid(),val);
}
}
void dequeue(struct QueueType* q,int *val,int i)/*出队列*/
{
if(q->out==q->in)
{
printf("queue is empty\n");
return;
}
else{
*val = q->value[q->out];
q->out = (q->out+1)%4;
printf("Customer %d has got the No.%d\n",i,*val);
}
}
void enter_shop(int j)
{
printf("Customer %d enter the barber shop.\n",j);
}
void sit_on_sofa(int j)
{
printf("Customer %d sit on the sofa.\n",j);
}
void get_up_from_sofa(int j)
{
printf("Customer %d get up from sofa.\n",j);
}
void sit_in_barber_chair(int j)
{
printf("Customer %d sit in the barber chair.\n",j);
}
void leave_barber_chair(int j)
{
printf("Customer %d leave the barber chair.\n",j);
}
void pay(int j)
{
printf("Customer %d pay the money.\n",j);
}
void exit_shop(int j)
{
printf("Customer %d exit shop.\n",j);
}
void accept_pay(int bnum)
{
printf("Barber %d accept the payment .\n",bnum);
printf("Barber %d has given the receipt .\n",bnum);
}
void cut_hair(int bnum)
{
sleep(0.5);
printf("Barber %d is cutting hair.\n",bnum);
printf("Barber %d has finished cutting hair.\n",bnum);
}
void customer(struct QueueType *queue,int i)
{
int chairnum;/*顾客取得的椅子号码*/
WAIT(MAX_CAPACITY,0);/*顾客等待进门*/
enter_shop(i);/*进门*/
WAIT(SOFA,0);/*等待沙发*/
sit_on_sofa(i);/*顾客在沙发上等待*/
WAIT(MUTEX,0);/***有空闲的理发师?***/
WAIT(queueLOCK,0);/*确保顾客从等待队列中取号码不被打断*/
//WAIT(MUTEX,0);/***有空闲的理发师?***/
dequeue(queue,&chairnum,i);/*顾客从队列中取得椅子号码*/
SIGNAL(queueLOCK,0);/*确保顾客从等待队列中取号码不被打断*/
WAIT(BARBER_CHAIR,chairnum);/*顾客等待自己号码的理发椅*/
get_up_from_sofa(i);/*顾客离开沙发*/
SIGNAL(SOFA,0);/*释放沙发资源*/
sit_in_barber_chair(i);/*顾客坐上理发椅*/
SIGNAL(CUST_READY,chairnum);/*顾客告之已在自己号码的理发椅上做好准备*/
WAIT(FINISHED,chairnum);/*顾客等待理发完成*/
leave_barber_chair(i);/*顾客离开理发椅*/
SIGNAL(LEAVE_B_CHAIR,chairnum);/*释放理发椅资源*/
//WAIT(CASHIER,0);/*等待收银员*/
pay(i);/*付帐*/
SIGNAL(PAYMENT,chairnum);/*顾客索要自己的收据*/
WAIT(RECEIPT,chairnum);/*顾客等待自己应得的收据*/
exit_shop(i);/*顾客离开理发店*/
SIGNAL(MAX_CAPACITY,0);/*释放理发店资源*/
}
void barber(int num,struct QueueType* queue)/*理发师同时兼职收银员*/
{
WAIT(queueLOCK,0);/*确保理发师发放顾客号码时不被打断*/
enqueue(queue,num);
SIGNAL(MUTEX,0);/***已有空闲的理发师***/
SIGNAL(queueLOCK,0);/*确保理发师发放顾客号码时不被打断*/
while(1) {
WAIT(CUST_READY,num);/*理发师等待,直到有一个顾客坐上自己的理发椅*/
cut_hair(num);/*理发过程*/
SIGNAL(FINISHED,num);/*告之自己的顾客已完成理发*/
WAIT(LEAVE_B_CHAIR,num);/*理发师等待自己的顾客从理发椅中站起*/
SIGNAL(BARBER_CHAIR,num);/*理发师在它的理发椅空时发信号*/
WAIT(PAYMENT,num);/*理发师接着等待收银*/
accept_pay(num);/*提供收据*/
SIGNAL(RECEIPT,num);/*告之自己的顾客已发出收据*/
//SIGNAL(CASHIER,0);/*确保收银过程不被打断*/
WAIT(queueLOCK,0);/*确保理发师取顾客号码时不被打断*/
enqueue(queue,num);
SIGNAL(MUTEX,0);/*已有空闲的理发师*/
SIGNAL(queueLOCK,0);/*确保理发师取顾客号码时不被打断*/
}
}
void create_barber(struct QueueType *queue,char* shmptr,pid_t pid)
{
int i;
for( i=0; i<3; i++ )
{
if( (pid = fork())<0 )
perror("fork error");
else if( pid == 0 )/*子进程*/
{
if( (shmptr = (char*) shmat(shmid,(char*)0,0) ) ==(char*)-1)
{
perror("get mermory shmat in child");
exit(4);
}
queue = (struct QueueType *)shmptr;
barber(i+1,queue);
shmdt(shmptr);/*删除物理链接*/
sleep(3);
_exit(0);
}
}
}
void create_customer1(struct QueueType *queue,char* shmptr,pid_t pid,int max)
{
int i;
for( i=0; i<max-3; i++ )
{
if( (pid = fork())<0 )
perror("fork error");
else if( pid == 0 )/*子进程*/
{
if( (shmptr = (char*) shmat(shmid,(char*)0,0) ) ==(char*)-1)
{
perror("get mermory shmat in child");
exit(4);
}
queue = (struct QueueType *)shmptr;
customer(queue,i+1);
shmdt(shmptr);/*删除物理链接*/
sleep(3);
_exit(0);
}
}
}
void create_customer2(struct QueueType *queue,char* shmptr,pid_t pid,int max,int av)
{
int i,upbound;
upbound=2*av+1;
srand( (unsigned int)time(NULL) );
for( i=0; i<max-3; i++ )
{
if( (pid = fork())<0 )
perror("fork error");
else if( pid == 0 )/*子进程*/
{
sleep( rand() % upbound );
if( (shmptr = (char*) shmat(shmid,(char*)0,0) ) ==(char*)-1)
{
perror("get mermory shmat in child");
exit(4);
}
queue = (struct QueueType *)shmptr;
customer(queue,i+1);
shmdt(shmptr);/*删除物理链接*/
sleep(3);
_exit(0);
}
}
}
int main( int argc, char *argv[] )
{
pid_t pid;
union semun arg;
int order;
int max;
int i=0;
key_t key;
char *shmptr;
static struct QueueType q;
struct QueueType *queue;
q.out = q.in = 0;
if(argc>2)
{
printf("usage: barbershop [number]\n");
exit(1);
}
max = (argc==1)?DEFAULT_N:(atoi(argv[1])+3);
if( (semid = semget( IPC_PRIVATE,23,IPC_CREAT|IPC_EXCL|0600))!=-1)
/*创建23个信号量,返回信号量ID*/
{
arg.array = start_val;
if( semctl( semid, 0, SETALL, arg )==-1 )
/*按arg.array指向的数组中的值设置该集合中所有信号量的值*/
{
perror("semctl error");
exit(1);
}
}
else if( ( semid = semget( IPC_PRIVATE, 23, 0 ))==-1 ) /*返回信号量ID*/
{
perror("semget error");
exit(2);
}
if( (shmid = shmget( IPC_PRIVATE, sizeof(q), IPC_CREAT|0600)) != -1)
/*创建共享存储区,返回一个共享存储标识符*/
{
if( (shmptr = (char*)shmat(shmid,0,0)) == (char*)-1 )/*连接到物理地址*/
{
perror("shmptr_parent_attach");
exit(1);
}
memcpy(shmptr,(char*)&q,sizeof(q));/*复制存储区*/
}
else
{
perror("shmid_parent_creation");
exit(2);
}
printf("\n***** Welcome to XMUCSD Barber Shop, cheap but best in the world! *****\n\n");
create_barber(queue,shmptr,pid);
//create_customer1(queue,shmptr,pid,max);
create_customer2(queue,shmptr,pid,max,2);
sleep(5);
shmctl(shmid,IPC_RMID,0);/*从系统中删去共享存储段*/
while(wait(0) != -1 && i++ < max-3);
if( semctl(semid,0,IPC_RMID,0)==-1 ) /*删除信号量集合*/
{
perror("semctl delete error");
exit(4);
}
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -