dp.h:
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/sem.h> #include <sys/msg.h> #include <sys/wait.h> /*信号灯控制用的共同体*/ typedef union semuns { int val; } Sem_uns; //管程中使用的信号量 class Sema{ public: Sema(int id); ~Sema(); int down(); //信号量加 1 int up(); //信号量减 1 private: int sem_id; //信号量标识符 }; //管程中使用的锁 class Lock{ public: Lock(Sema *lock); ~Lock(); void close_lock(); void open_lock(); private: Sema *sema; //锁使用的信号量 }; //管程中使用的条件变量 class Condition{ public: Condition(Sema *sema1, Sema *sema2); ~Condition(); void Wait(Lock *conditionLock,int direct); //条件变量阻塞操作 int Signal(int direct); //条件变量唤醒操作 private: Sema *sema0; //一个方向的阻塞队列 Sema *sema1;//另一个方向的阻塞队列 Lock*lock;//进入管程时获取的锁 }; //管程的定义 class dp{ public: dp(int maxall,int maxcur); //管程构造函数 ~dp(); void Arrive(int direct); //准备上车道 void Cross(int direct); //已在车道上 void Quit(int direct);//下了车道 int*eastCount;//各种情况和状态下的数量 int*westCount; int*eastWait; int*westWait; int*sumPassedCars; //建立或获取 ipc 信号量的一组函数的原型说明 int get_ipc_id(char *proc_file,key_t key); int set_sem(key_t sem_key,int sem_val,int sem_flag); //创建共享内存,放行车状态 char *set_shm(key_t shm_key,int shm_num,int shm_flag); private: int rate ;//控制执行速度也代表车速 int*maxCars;//最⼤同向车辆数 int*numCars;//当前正通过的车辆数 int*currentDire;//当前正通过的车辆的⽅向 Lock *lock; //控制互斥进入管程的锁 Condition *OneWayFull; //通过单行道的条件变量 };
dp.cc:
#include "dp.h" using namespace std; Sema::Sema(int id) { sem_id = id; } Sema::~Sema(){ } /* * 信号灯上的 down/up 操作 * semid:信号灯数组标识符 * semnum:信号灯数组下标 * buf:操作信号灯的结构 */ int Sema::down() { 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 Sema::up() { Sem_uns arg; 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; } /* * 用于哲学家管程的互斥执行 */ Lock::Lock(Sema * s) { sema = s; } Lock::~Lock(){ } //上锁 void Lock::close_lock() { sema->down(); } //开锁 void Lock::open_lock() { sema->up(); } //用于行车问题的条件变量 Condition::Condition(Sema *semax1 ,Sema *semax2){ sema0=semax1; sema1=semax2; } /* * 行车条件成立,状态变为通过 * 否则睡眠,等待条件成立 */ void Condition::Wait(Lock *lock,int direc) { if(direc==0){ cout<<getpid()<<"号车向东等待单行道\n"; lock->open_lock();//开锁 sema0->down();//等待 lock->close_lock();//上锁 } else if(direc==1){ cout<<getpid()<<"号车向西等待单行道\n"; lock->open_lock();//开锁 sema1->down();//等待 lock->close_lock();//上锁 } } int Condition::Signal(int direc) { int i; if(direc==0) { //可行车,唤醒一个方向 i=sema0->up(); } else if(direc==1) { //可行车,唤醒一个方向 i=sema1->up(); } return i; } Condition::~Condition(){} int dp::get_ipc_id(char *proc_file,key_t key) { #define BUFSZ 256 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; } /* * set_sem 函数建立一个具有 n 个信号灯的信号量 * 如果建立成功,返回 一个信号量的标识符 sem_id * 输入参数: * sem_key 信号量的键值 * sem_val 信号量中信号灯的个数 * sem_flag 信号量的存取权限 */ int dp::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_shm 函数建立一个具有 n 个字节 的共享内存区 * 如果建立成功,返回 一个指向该内存区首地址的指针 shm_buf * 输入参数: * shm_key 共享内存的键值 * shm_val 共享内存字节的长度 * shm_flag 共享内存的存取权限 */ char * dp::set_shm(key_t shm_key,int shm_num,int shm_flg) { int i,shm_id; char * shm_buf; //测试由 shm_key 标识的共享内存区是否已经建立 if((shm_id=get_ipc_id("/proc/sysvipc/shm",shm_key))<0){ //shmget 新建 一个长度为 shm_num 字节的共享内存 if((shm_id= shmget(shm_key,shm_num,shm_flg)) <0){ perror("shareMemory set error"); exit(EXIT_FAILURE); } //shmat 将由 shm_id 标识的共享内存附加给指针 shm_buf 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; //初始为 0 } //共享内存区已经建立,将由 shm_id 标识的共享内存附加给指针 shm_buf if((shm_buf = (char *)shmat(shm_id,0,0)) < (char *)0) { perror("get shareMemory error"); exit(EXIT_FAILURE); } return shm_buf; } //行车问题管程构造函数 dp::dp(int maxall,int maxcur) { int ipc_flg = IPC_CREAT | 0644; Sema*sema0; Sema*sema1; Sema*semaLock; maxCars=(int*)set_shm(100,1,ipc_flg);//最⼤单向 numCars=(int*)set_shm(200,1,ipc_flg);//当前⽅向上通过的总的车辆辆 currentDire=(int*)set_shm(300,1,ipc_flg);//当前⽅向0是东1是西 eastCount=(int*)set_shm(501,1,ipc_flg); westCount=(int*)set_shm(502,1,ipc_flg); sumPassedCars=(int*)set_shm(700,1,ipc_flg); eastWait=(int*)set_shm(801,1,ipc_flg); westWait=(int*)set_shm(802,1,ipc_flg); int sema0_id=set_sem(401,0,ipc_flg); int sema1_id=set_sem(402,0,ipc_flg); int semaLock_id=set_sem(601,maxcur,ipc_flg); *maxCars=maxcur; *numCars=0; *currentDire=0; *eastCount=0; *westCount=0; *sumPassedCars=0; *eastWait=0; *westWait=0; sema0=new Sema(sema0_id); sema1=new Sema(sema1_id); semaLock=new Sema(semaLock_id); lock=new Lock(semaLock); OneWayFull=new Condition(sema0,sema1); } //行车的操作 void dp::Arrive(int direc){ lock->close_lock();//进入管程,上锁 //如果当前⽅向不是我的⽅向或者单⾏道上有车且车辆数⼤于等于上限数 if((*currentDire!=direc||*numCars>=*maxCars)&*sumPassedCars>0){ if(direc==0){ *eastWait+=1; } else if(direc==1){ *westWait+=1; } OneWayFull->Wait(lock,direc); //测试是否能上道 } if(direc==0){//东+1 *eastWait-=1; *eastCount=*eastCount+1; cout<<getpid()<<"号车向东进⼊单⾏道\n"; } else if(direc==1){ *westCount=*westCount+1; *westWait-=1; cout<<getpid()<<"号车向西进⼊单⾏道\n"; } *numCars=*numCars+1; *currentDire=direc; *sumPassedCars+=1; sleep(3);//通过用了 rate 秒 lock->open_lock();//离开管程,开锁 } void dp::Cross(int direc){ lock->close_lock();//进入管程,上锁 if(direc==0) cout<<getpid()<<"号车向东通过单⾏道,道上车数:"<<*numCars<<"\n"; else if(direc==1) cout<<getpid()<<"号车向西通过单⾏道,道上车数:"<<*numCars<<"\n"; lock->open_lock();//离开管程,开锁 sleep(6); } void dp::Quit(int direc){ lock->close_lock(); *numCars-=1; if(direc==0) cout<<getpid()<<"号车向东离开单⾏道"<<"\n"; else if(direc==1) cout<<getpid()<<"号车向西离开单⾏道"<<"\n"; if(*numCars==0){ if(direc==0){ if(*westWait>0){ OneWayFull->Signal(1); } else if(*eastWait>0){ OneWayFull->Signal(0); } } else if(direc==1){ if(*eastWait>0){ OneWayFull->Signal(0); } else if(*westWait>0){ OneWayFull->Signal(1); } } } lock->open_lock(); } dp::~dp(){ } // 行车问题并发执行的入口 int main(int argc,char *argv[]) { //管程对象的指针 int maxCars; int maxSingelDirect; cout<<"输⼊总车辆数:"; cin>>maxCars; cout<<"输⼊单向通过的最⼤车数:"; cin>>maxSingelDirect; dp *tdp=new dp(maxCars,maxSingelDirect); int i; int pid[maxCars]; int direc; for(i=0;i<maxCars;i++){ direc=rand()%2;//决定东西⽅向 pid[i]=fork(); //建立进程 if(pid[i]==0){ sleep(2); tdp->Arrive(direc);//进⼊ tdp->Cross(direc);//通过 tdp->Quit(direc);//离开 exit(EXIT_SUCCESS); } } for(i=0;i<maxCars;i++){ waitpid(pid[i],NULL,0); } cout<<*(tdp->eastCount)<<"辆向东"<<*(tdp->westCount) <<"辆向西,正常通过.\n"; delete tdp; return 0; }
Makefile:
head = dp.h
srcs = dp.cc
objs = dp.o
opts = -w -g -c
all: dp
dp: $(objs)
g++ $(objs) -o dp
dp.o: $(srcs) $(head)
g++ $(opts) $(srcs)
clean:
rm dp *.o