Chinaunix首页 | 论坛 | 博客
  • 博客访问: 880178
  • 博文数量: 254
  • 博客积分: 5350
  • 博客等级: 大校
  • 技术积分: 2045
  • 用 户 组: 普通用户
  • 注册时间: 2008-06-27 13:27
文章分类

全部博文(254)

文章存档

2015年(1)

2014年(9)

2013年(17)

2012年(30)

2011年(150)

2010年(17)

2009年(28)

2008年(2)

分类: C/C++

2012-02-15 14:19:02

进程互斥实验
/*
理发店问题:假设理发店的理发室中有 3 个理发椅子和 3 个理发师,有一个可容
纳 4 个顾客坐等理发的沙发。此外还有一间等候室,可容纳 13 位顾客等候进入理发
室。顾客如果发现理发店中顾客已满(超过 20 人),就不进入理发店。
   在理发店内,理发师一旦有空就为坐在沙发上等待时间最长的顾客理发,同时
空出的沙发让在等候室中等待时间最长的的顾客就坐。顾客理完发后,可向任何一
位理发师付款。但理发店只有一本现金登记册,在任一时刻只能记录一个顾客的付
款。理发师在没有顾客的时候就坐在理发椅子上睡眠。理发师的时间就用在理发、
收款、睡眠上。
请利用 linux 系统提供的 IPC 进程通信机制实验并实现理发店问题的一个解法。
*/
//ipc.h
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define BUFSZ 256

typedef union semuns {
int val;
}Sem_uns;
struct msgbuf {
long mtype;
int mid;
};


struct Q{
int front,back;
int data[100];
};


void q_init(struct Q*);
void push(struct Q*,int);
int pop(struct Q*);

int get_ipc_id(char *proc_file,key_t key);
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);

void init_key();

key_t ready_key;
int ready_id;

key_t go_key;
int go_id;

key_t go2sofa_key;
int go2sofa_id;

key_t request_key;
int request_id;

key_t come_key;
int come_id;

key_t bar_key;
int bar_sem;

key_t account_key;
int account_sem;

key_t come2sofa_key;
int come2sofa_id;

//ipc.c

#include "ipc.h"
/*
* get_ipc_id() 从/proc/sysvipc/文件系统中获取 IPC 的 id 号
* pfile: 对应/proc/sysvipc/目录中的 IPC 文件分别为
*              msg-消息队列,sem-信号量,shm-共享内存
* key: 对应要获取的 IPC 的 id 号的键值
*/
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;
}
/*
* 信号灯上的 down/up 操作
* semid:信号灯数组标识符
* semnum:信号灯数组下标
* buf:操作信号灯的结构
*/
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;
}
/*
* set_sem 函数建立一个具有 n 个信号灯的信号量
如果建立成功,返回 一个信号灯数组的标识符 sem_id
*
输入参数:
*
* sem_key 信号灯数组的键值
* sem_val 信号灯数组中信号灯的个数
* sem_flag 信号等数组的存取权限
*/
int set_sem(key_t sem_key,int sem_val,int sem_flg)
{
int sem_id;
Sem_uns sem_arg;
//测试由 sem_key 标识的信号灯数组是否已经建立
if((sem_id = get_ipc_id("/proc/sysvipc/sem",sem_key)) < 0){
    //semget 新建一个信号灯,其标号返回到 sem_id
    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;
}
/*
* set_msq 函数建立一个消息队列
* 如果建立成功,返回 一个消息队列的标识符 msq_id
* 输入参数:
* msq_key 消息队列的键值
* msq_flag 消息队列的存取权限
*/
int set_msq(key_t msq_key,int msq_flg)
{
int msq_id;
//测试由 msq_key 标识的消息队列是否已经建立
if((msq_id = get_ipc_id("/proc/sysvipc/msg",msq_key)) < 0 ){
    //msgget 新建一个消息队列,其标号返回到 msq_id
    if((msq_id = msgget(msq_key,msq_flg)) < 0){
      perror("messageQueue set error");
      exit(EXIT_FAILURE);
    }
}
return msq_id;
}

void init_key(){
ready_key=100;
go_key=200;
go2sofa_key=300;
request_key=400;
come_key=500;
come2sofa_key=600;
bar_key=700;
account_key=800;
}

void q_init(struct Q *q){
q->front=0;
q->back=0;
}
void push(struct Q *q,int id){
q->data[q->front]=id;
q->front=(q->front+1)%100;
}
int pop(struct Q *q){
int buf=q->data[q->back];
q->back=(q->back+1)%100;
return buf;
}


.//barbour.c
//模拟理发师

#include "ipc.h"
int main(int argc,char *argv[]){
int rate1=10;
int rate2=2;
if(argc>1){
    rate1=atoi(argv[1]);
}
if(argc>2){
    rate2=atoi(argv[2]);
}
init_key();
int flg=IPC_CREAT|0666;
ready_id=set_msq(ready_key,flg);
request_id=set_msq(request_key,flg);
go_id=set_msq(go_key,flg);
bar_sem=set_sem(bar_key,3,flg);
account_sem=set_sem(account_key,1,flg);
struct msgbuf Msg_buf;
while(1){
    Msg_buf.mtype=1;
    Msg_buf.mid=getpid();
    msgsnd(ready_id,&Msg_buf,sizeof(int),0);
    printf("Barbour %d is ready.\n",getpid());
    msgrcv(request_id,&Msg_buf,sizeof(int),getpid(),0);
    down(bar_sem);
    printf("Customer %d is being served by Barbour %d.\n",Msg_buf.mid,getpid());
    sleep(rate1);
    printf("Customer %d goes to pay for Barbour %d's service.\n",Msg_buf.mid,getpid());
    down(account_sem);
    sleep(rate2);
    up(account_sem);
    printf("Customer %d goes out of the Barbour's House.\n",Msg_buf.mid);
    Msg_buf.mtype=1;
    msgsnd(go_id,&Msg_buf,sizeof(int),0);
    up(bar_sem);
}
return EXIT_SUCCESS;
}

//sofa_control
//模拟沙发上的情况

#include "ipc.h"
int main(int argc,char *argv[]){
int on_sofa=0;
int flg=IPC_CREAT|0666;
init_key();
go2sofa_id=set_msq(go2sofa_key,flg);
come2sofa_id=set_msq(come2sofa_key,flg);
request_id=set_msq(request_key,flg);
ready_id=set_msq(ready_key,flg);
struct msgbuf Msg_buf;
struct Q sofa_q;
q_init(&sofa_q);
while(1){
    if(on_sofa<4){
      Msg_buf.mtype=1;
      msgsnd(come2sofa_id,&Msg_buf,sizeof(int),0);
      if(msgrcv(go2sofa_id,&Msg_buf,sizeof(int),1,IPC_NOWAIT)>=0){
        ++on_sofa;
        printf("Customer %d goes to sofa.\n",Msg_buf.mid);
        push(&sofa_q,Msg_buf.mid);
      }
    }
    if(on_sofa>0){
      if(msgrcv(ready_id,&Msg_buf,sizeof(int),1,IPC_NOWAIT)>=0){
        --on_sofa;
        Msg_buf.mtype=Msg_buf.mid;
        Msg_buf.mid=pop(&sofa_q);
        printf("Customer %d goes to Barbour %d.\n",Msg_buf.mid,(int)Msg_buf.mtype);
        msgsnd(request_id,&Msg_buf,sizeof(int),0);
      }
    }
}
return EXIT_SUCCESS;
}

//room_control.c
//模拟等候室的情况
#include "ipc.h"
int main(int argc,char *argv[]){
int in_room=0;
init_key();

int flg=IPC_CREAT|0666;
come_id=set_msq(come_key,flg);
request_id=set_msq(request_key,flg);
go2sofa_id=set_msq(go2sofa_key,flg);
come2sofa_id=set_msq(come2sofa_key,flg);
struct msgbuf Msg_buf;
struct Q room_q;
q_init(&room_q);
while(1){
    if(in_room<13){
      if(msgrcv(come_id,&Msg_buf,sizeof(int),1,IPC_NOWAIT)>=0){
        ++in_room;
        printf("Customer %d goes in the waiting room.\n",Msg_buf.mid);
        push(&room_q,Msg_buf.mid);
      }
    }
    if(in_room>0){
      int state=msgrcv(come2sofa_id,&Msg_buf,sizeof(int),1,IPC_NOWAIT);
      if(state>=0){
        --in_room;
        Msg_buf.mtype=1;
        Msg_buf.mid=pop(&room_q);
        printf("Customer %d goes to the sofa.\n",Msg_buf.mid);
        msgsnd(go2sofa_id,&Msg_buf,sizeof(int),0);
      }
    }
}
return EXIT_SUCCESS;
}

//customer.c
//模拟顾客来到理发店
#include "ipc.h"
int main(int argc,char *argv[]){
int rate=5;
if(argc>1){
    rate=atoi(argv[1]);
}
init_key();
int flg=IPC_CREAT|0666;
go_id=set_msq(go_key,flg);
come_id=set_msq(come_key,flg);
int total=0,cid=0;
struct msgbuf Msg_buf;
srand((unsigned int)time(NULL));
while(1){
    int state;
    while((state=msgrcv(go_id,&Msg_buf,sizeof(int),1,IPC_NOWAIT))>=0){
      --total;
    }
    if(total<20){
      Msg_buf.mtype=1;
      Msg_buf.mid=cid;
      msgsnd(come_id,&Msg_buf,sizeof(int),0);
      printf("Customer %d goes in the Barbour's House.\n",cid);
      ++total;
      ++cid;
    }
    else{
      printf("A customer goes to the Barbour's House but it's full.\n");
    }
    sleep(rand()%10);
}
return EXIT_SUCCESS;
}
//removeipc.c
//用来清除建立的消息队列和信号灯
#include "ipc.h"
int main(){
init_key();
int id;
Sem_uns sem_arg;
if((id=get_ipc_id("/proc/sysvipc/sem",bar_key))>=0){
    semctl(id,0,IPC_RMID,sem_arg);
}
if((id=get_ipc_id("/proc/sysvipc/sem",account_key))>=0){
    semctl(id,0,IPC_RMID,sem_arg);
}
if((id=get_ipc_id("/proc/sysvipc/msg",ready_key))>=0){
    msgctl(id,IPC_RMID,NULL);
}
if((id=get_ipc_id("/proc/sysvipc/msg",go_key))>=0){
    msgctl(id,IPC_RMID,NULL);
}
if((id=get_ipc_id("/proc/sysvipc/msg",go2sofa_key))>=0){
    msgctl(id,IPC_RMID,NULL);
}
if((id=get_ipc_id("/proc/sysvipc/msg",request_key))>=0){
    msgctl(id,IPC_RMID,NULL);
}
if((id=get_ipc_id("/proc/sysvipc/msg",come_key))>=0){
    msgctl(id,IPC_RMID,NULL);
}
if((id=get_ipc_id("/proc/sysvipc/msg",come2sofa_key))>=0){
    msgctl(id,IPC_RMID,NULL);
}
return 0;
}


//Makefile

head = ipc.h
bar_srcs = ipc.c barbour.c
bar_objs = ipc.o barbour.o
sofa_srcs = ipc.c sofa_control.c
sofa_objs = ipc.o sofa_control.o
room_srcs = ipc.c room_control.c
room_objs = ipc.o room_control.o
c_srcs = ipc.c customer.c
c_objs = ipc.o customer.o
remove_srcs = ipc.c removeipc.c
remove_objs = ipc.o removeipc.o
opts = -Wall -g -c

all:    barbour sofa_control room_control customer removeipc
barbour:    $(bar_objs)
    gcc $(bar_objs) -o barbour
barbour.o:    $(bar_srcs) $(head)
    gcc $(opts) $(bar_srcs)
sofa_control:    $(sofa_objs)
    gcc $(sofa_objs) -o sofa_control
sofa_control.o:    $(sofa_srcs) $(head)
    gcc $(opts) $(sofa_srcs)
room_control: $(room_objs)
    gcc $(room_objs) -o room_control
room_control.o:    $(room_srcs) $(head)
    gcc $(opts) $(room_srcs)
customer:    $(c_objs)
    gcc $(c_objs) -o customer
customer.o:    $(c_srcs) $(head)
    gcc $(opts) $(c_srcs)
removeipc:    $(remove_objs)
    gcc $(remove_objs) -o removeipc
removeipc.o:    $(remove_srcs) $(head)
    gcc $(opts) $(remove_srcs)
clean:
    rm *.o
阅读(1423) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~