操作系統實驗五

實驗內容:

理髮店問題:假設理髮店的理髮室中有3個理髮椅子和3個理髮師,有一個可容納4個顧客坐等理髮的沙發。此外還有一間等候室,可容納13位顧客等候進入理髮室。顧客如果發現理髮店中顧客已滿(超過20人),就不進入理髮店。在理髮店內,理髮師一旦有空就爲坐在沙發上等待時間最長的顧客理髮,同時空出的沙發讓在等候室中等待時間最長的的顧客就坐。顧客理完髮後,可向任何一位理髮師付款。但理髮店只有一本現金登記冊,在任一時刻只能記錄一個顧客的付款。理髮師在沒有顧客的時候就坐在理髮椅子上睡眠。理髮師的時間就用在理髮、收款、睡眠上。請利用linux系統提供的IPC進程通信機制實驗並實現理髮店問題的一個解法。

二.實驗思路:

1.因爲有三個理髮師和三把理髮椅,理髮師和理髮椅是一一對應的,所以可以忽略理髮椅而直接將它和理髮師視爲一體,因爲三個理髮師進行的是同樣的動作——理髮、睡眠和收款,所以需要利用fork()調用建立兩個子進程,和父進程一起用來分別代表三個理髮師。

2.因爲開始沒顧客,所以理髮師一開始都直接進入休眠狀態。

3. 因爲理髮店只有一本現金登記冊,在任一時刻只能記錄一個顧客的付款,所以應設一個互斥信號量account_sem用來控制理髮師對登記冊的修改訪問。

4.因爲沙發只有4個,等候室只能有13個人呆在裏面,所以要設兩個數sofa_count和wait_count,用來記錄當前在沙發上和在等候室裏的人數,以分別控制人數不超過要求。並且爲防止多個進程同時對這兩個數進行修改造成混亂,應設置一個互斥信號量count_sem 用來控制進程對這兩個數的修改。

5.建立四個 消息隊列sofa_quest_flg,sofa_respond_flg和

wait_quest_flg,wait_respond_flg;sofa_quest_flg用來記錄當前請求剪髮的消息,相當於擺在醫生桌面上的病例,理髮師通過檢查該消息隊列來判斷有沒有顧客等待理髮,若沒有則睡眠。sofa_respond_flg用來記錄理髮師完成剪髮的消息。Wait_quest_flg用來記錄請求沙發座位的消息,wait_respond_flg用來記錄請求到沙發座位的消息。如果理髮師空閒,則檢查sofa_quest_flg看有沒有顧客等待理髮,如果沙發當前沒有坐滿則看等候室裏是否有人,有人則檢查wait_quest_flg隊列來選取等候最久的人坐到沙發上。檢查sofa_respond_flg隊列,如果裏面有消息,則說明有顧客完成理髮,則把沙發當前的人數sofa_count減一;檢查wait_respond_flg,如果裏面有消息,則說明有顧客從等候室進入沙發,則把等候室當前的人數wait_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>

#define BUFSZ 256
#define WRITERQUEST 1
#define READERQUEST 2
#define FINISHED 3

typedef union semuns{
	int val;
}Sem_uns;

typedef struct msgbuf{
	long mtype;
	int mid;
}Msg_buf;
key_t account_key;
int account_sem;

key_t count_key;
int count_sem;

int sem_val;
int sem_flg;

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;

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);

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("share memory 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;
}
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){
if((msq_id=msgget(msq_key,msq_flg))<0){
perror("messageQueue set error");
exit(EXIT_FAILURE);
}
}
return msq_id;}

barber.c:
#include"ipc.h"
int main(int argc,char*argv[]){
int rate;	
Msg_buf msg_arg;
if(argv[1]!=NULL) rate=atoi(argv[1]);
else rate=3;
wait_quest_flg=IPC_CREAT|0644;
wait_quest_key=101;
wait_quest_id=set_msq(wait_quest_key,wait_quest_flg);
wait_respond_flg=IPC_CREAT|0644;
wait_respond_key=102;
wait_respond_id=set_msq(wait_respond_key,wait_respond_flg);
sofa_quest_flg=IPC_CREAT|0644;
sofa_quest_key=201;
sofa_quest_id=set_msq(sofa_quest_key,sofa_quest_flg);
sofa_respond_flg=IPC_CREAT|0644;
sofa_respond_key=202;
sofa_respond_id=set_msq(sofa_respond_key,sofa_respond_flg);
account_key=301;
count_key=302;
sem_flg=IPC_CREAT|0644;
sem_val=1;
account_sem=set_sem(account_key,sem_val,sem_flg);
sem_val=1;
count_sem=set_sem(count_key,sem_val,sem_flg);
int pid1,pid2;
if((pid1=fork())==0){
while(1){
printf("%d號理髮師睡眠\n",getpid());
if(msgrcv(sofa_quest_id,&msg_arg,sizeof(msg_arg),0,0)>=0){
msgsnd(sofa_respond_id,&msg_arg,sizeof(msg_arg),0);
printf("%d號理髮師爲%d號顧客理髮\n",getpid(),msg_arg.mid);
sleep(rate);
down(account_sem);
printf("%d號理髮師爲%d號顧客收款\n",getpid(),msg_arg.mid);
up(account_sem);
}
}
}else if((pid2=fork())==0){
while(1){
printf("%d號理髮師睡眠\n",getpid());
if(msgrcv(sofa_quest_id,&msg_arg,sizeof(msg_arg),0,0)>=0){
msgsnd(sofa_respond_id,&msg_arg,sizeof(msg_arg),0);
printf("%d號理髮師爲%d號顧客理髮\n",getpid(),msg_arg.mid);
sleep(rate);
down(account_sem);
printf("%d號理髮師爲%d號顧客收款\n",getpid(),msg_arg.mid);
up(account_sem);
}
}
}else{
while(1){
printf("%d號理髮師睡眠\n",getpid());
if(msgrcv(sofa_quest_id,&msg_arg,sizeof(msg_arg),0,0)>=0){
msgsnd(sofa_respond_id,&msg_arg,sizeof(msg_arg),0);
printf("%d號理髮師爲%d號顧客理髮\n",getpid(),msg_arg.mid);
sleep(rate);
down(account_sem);
printf("%d號理髮師爲%d號顧客收款\n",getpid(),msg_arg.mid);
up(account_sem);
}
}
}
return EXIT_SUCCESS;
}

Customer.c:
#include"ipc.h"
int main(int argc,char* argv[])
{
int rate;
Msg_buf msg_arg;
if(argv[1]!=NULL) rate=atoi(argv[1]);
else rate=3;
wait_quest_flg=IPC_CREAT|0644;
wait_quest_key=101;
wait_quest_id=set_msq(wait_quest_key,wait_quest_flg);
wait_respond_flg=IPC_CREAT|0644;
wait_respond_key=102;
wait_respond_id=set_msq(wait_respond_key,wait_respond_flg);
sofa_quest_flg=IPC_CREAT|0644;
sofa_quest_key=201;
sofa_quest_id=set_msq(sofa_quest_key,sofa_quest_flg);
sofa_respond_flg=IPC_CREAT|0644;
sofa_respond_key=202;
sofa_respond_id=set_msq(sofa_respond_key,sofa_respond_flg);
account_key=301;
count_key=302;
sem_flg=IPC_CREAT|0644;
sem_val=1;
account_sem=set_sem(account_key,sem_val,sem_flg);
sem_val=1;
count_sem=set_sem(count_key,sem_val,sem_flg);
wait_quest_flg=IPC_CREAT|0644;
wait_quest_key=101;
wait_quest_id=set_msq(wait_quest_key,wait_quest_flg);
wait_respond_flg=IPC_CREAT|0644;
wait_respond_key=102;
wait_respond_id=set_msq(wait_respond_key,wait_respond_flg);
sofa_quest_flg=IPC_CREAT|0644;
sofa_quest_key=201;
sofa_quest_id=set_msq(sofa_quest_key,sofa_quest_flg);
sofa_respond_flg=IPC_CREAT|0644;
sofa_respond_key=202;
sofa_respond_id=set_msq(sofa_respond_key,sofa_respond_flg);
account_key=301;
count_key=302;
sem_flg=IPC_CREAT|0644;
sem_val=1;
account_sem=set_sem(account_key,sem_val,sem_flg);
sem_val=1;
count_sem=set_sem(count_key,sem_val,sem_flg);
int wait_count=0;
int sofa_count=0;
int i=0;
while(1){
sleep(rate);
down(count_sem);
i++;
up(count_sem);
msg_arg.mid=i;
if(sofa_count>=0){
msgsnd(sofa_quest_id,&msg_arg,sizeof(msg_arg),0)
}
if(sofa_count<4){
if(wait_count!=0){
msgrcv(wait_quest_id,&msg_arg,sizeof(msg_arg),0,0);
msgsnd(wait_respond_id,&msg_arg,sizeof(msg_arg),0);
printf("%d號顧客從等候室坐到沙發上\n",msg_arg.mid);
}
else{
printf("%d號顧客從外面進來坐到沙發上\n",msg_arg.mid);
}
down(count_sem);
sofa_count++;
up(count_sem);
}
else if(wait_count<13){
printf("沙發已滿,%d號顧客進入等候室等待\n",msg_arg.mid);
msgsnd(wait_quest_id,&msg_arg,sizeof(msg_arg),0);
down(count_sem);
wait_count++;
up(count_sem);
}
else{
printf("理髮店已滿%d號顧客沒有進入理髮店\n",msg_arg.mid);
}
wait_respond_flg=IPC_NOWAIT;
if(msgrcv(wait_respond_id,&msg_arg,sizeof(msg_arg),0,wait_respond_flg)>=0){
down(count_sem);
wait_count--;
up(count_sem);
}
sofa_respond_flg=IPC_NOWAIT;
if(msgrcv(sofa_respond_id,&msg_arg,sizeof(msg_arg),0,sofa_respond_flg)>=0){
down(count_sem);
sofa_count--;
up(count_sem);
}
}
return EXIT_SUCCESS;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章