操作系统实验六. 死锁问题实验——单车道问题

问题:

在两个城市南北方向之间存在一条铁路,多列火车可以分别从两个城市的车站
排队等待进入车道向对方城市行驶,该铁路在同一时间,只能允许在同一方向上行
车,如果同时有相向的火车行驶将会撞车。请模拟实现两个方向行车,而不会出现
撞车或长时间等待的情况。您能构造一个管程来解决这个问题吗?

解法:
结合代码来看,每一步都有注释:
关键代码部分是Wait(),Arrive(),Cross(),Quit();对于火车的进入和离开,分别建立两个锁,当某辆车(进程)进入时获取进入锁,执行完arrive释放进入锁,以供下一个车获取进入锁,如果获取进入锁的车不符合条件,那么wait(),等到车道上的车都离开了且发送signal信号,wait()的阻塞状态被解开,这辆车就能够进入车道,并释放进入锁。遵循FIFO原则,不会存在长时间等待现象。
离开锁就是同时间每次只能有一辆车离开车道。
(PS:注释里的中文是指导书自带的,由于在英文版ubuntu里编程,所以我写的注释都是英文的,看不懂的朋友可以直接用网易有道云词典翻译)
下面的代码都复制到一个文件夹里去,编写makefile之后在终端make就可以运行啦。
在这里插入图片描述
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 direc); //条件变量唤醒操作
private:
    Sema *sema0; //a block queue of one way
    Sema *sema1; //the other
    Lock *lock; //the lock acquired when entering the tube;
};
class OneWay{
public:
    OneWay (int maxall,int maxcur);
        ~OneWay();
    void Arrive(int direc);//car is about to ride on oneway
    void Cross(int direc);//on the oneway
    void Quit(int direc);//pass the oneway
    int *eastCount;//tot
    int *westCount;//tot
    int *eastWait;
    int *westWait;
    int *sumPassedCars;//total amount of already passed cars;
private:
    //build functions to get ipc sema;
    int get_ipc_id(char *proc_file,key_t key);
    int set_sem(key_t sem_key,int sem_val,int sem_flag);
    //create sharing memory
    char *set_shm(key_t shm_key,int shm_num,int shm_flag);
    int rate;//velocity of the car;
    int *maxCars;//max amount of cars in the same direction
    int *numCars;//amount of cars which is passing;
    int *currentDire;// current crossing car's direction
    Condition *condition;// condition variable to cross the oneway
    Lock *lock1,*lock2,*lock3;
};

Dp.cpp

#include "dp.h"
using namespace std;
#define BUFSZ 256
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;
}
/*
* 用于oneway管程的互斥执行
*/
Lock::Lock(Sema * s)
{
    sema = s;
}
Lock::~Lock(){ }
//上锁
void Lock::close_lock()
{
sema->down();
}
//开锁
void Lock::open_lock()
{
sema->up();
}
int OneWay::get_ipc_id(char *proc_file,key_t key){
    FILE *pf;
    int i,j;
    char line[BUFSZ],column[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]!=' '){
            column[j++]=line[i++];
        }
        column[j]='\0';
        if(atoi(column)!=key)
            continue;
        j=0;
        while(line[i]==' ')
            i++;
        while(line[i]!=' '){
            column[j++]=line[i++];
        }
        column[j]='\0';
        i=atoi(column);
        fclose(pf);
        return i;
    }
    fclose(pf);
    return -1;
}
/*
*
set_sem 函数建立一个具有 n 个信号灯的信号量
*
如果建立成功,返回 一个信号量的标识符 sem_id
*
输入参数:
*
sem_key 信号量的键值
*
sem_val 信号量中信号灯的个数
*
sem_flag 信号量的存取权限
*/
int OneWay::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 * OneWay::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;
}            
Condition::Condition(Sema *semax1,Sema *semax2){
    sema0=semax1;
    sema1=semax2;
}
/*
* check if it can pass
*/
void Condition::Wait(Lock *lock,int direc){
    if(direc == 0){
      // cout<<getpid()<<"car is waiting oneway,direct to east"<<endl;
        //lock->open_lock();
        sema0->down();
        //lock->close_lock();
    }
    else if(direc==1){
      //  cout<<getpid()<<"car is waiting oneway,direct to west"<<endl;
       // lock->open_lock();
        sema1->down();
       // lock->close_lock();
    }
}
int Condition::Signal(int direc){
    int i;
    if(direc==0)//wake up a direction
    {
        i=sema0->up();
    }
    else if(direc==1){
        i=sema1->up();
    }
    return i;
}
Condition::~Condition(){}
OneWay::OneWay(int maxall,int maxcur){
    Sema *sema0;
    Sema *sema1;
    Sema *semaLock1,*semaLock2,*semaLock3;
    int ipc_flg=IPC_CREAT|0644;
    maxCars=(int *) set_shm(100,1,ipc_flg);
    numCars=(int *) set_shm(200,1,ipc_flg);
    currentDire=(int *) set_shm(300,1,ipc_flg);
    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_fl/g);
    int sema1_id=set_sem(402,0,ipc_flg);
    int semaLock1_id=set_sem(601,maxcur,ipc_flg);
    int semaLock2_id=set_sem(602,maxcur,ipc_flg);
    int semaLock3_id=set_sem(603,maxcur,ipc_flg);
    //init
    *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);
    semaLock1=new Sema(semaLock1_id);
    semaLock2=new Sema(semaLock2_id);
    semaLock3=new Sema(semaLock3_id);
    lock1=new Lock(semaLock1);
    lock2=new Lock(semaLock2);
    lock3=new Lock(semaLock3);
    condition=new Condition(sema0,sema1);
}
void OneWay::Arrive(int direc){
    lock1->close_lock();//FIFO,if lock1 is already taken by a different direction,then stop and wait
    if((*currentDire!=direc||*numCars>=*maxCars)&*sumPassedCars>0)
    {
        if(direc==0){
            *eastWait+=1;
        }
        else if(direc==1){
            *westWait+=1;
        }
        condition->Wait(lock1,direc);
        if(direc==0){
            *eastWait-=1;
        }
        else if(direc==1){
            *westWait-=1;
        }
    
    }// cout<<"ddddd"<<endl;
    *currentDire=direc;
    *numCars=*numCars+1;
    *sumPassedCars+=1; 
    lock1->open_lock();
    if(direc==0){
        //*eastWait-=1;//这个地方出bug了
        *eastCount=*eastCount+1;
        cout<<getpid()<<"car ride into oneway,direct to east"<<endl;
    }
    else if(direc==1){
        //*westWait-=1;
        *westCount=*westCount+1;
        cout<<getpid()<<"car ride into oneway,direct to west"<<endl;
    } 
    
}
void OneWay::Cross(int direc){
    //lock2->close_lock();
    if(direc==0){
        cout<<getpid()<<"car pass through oneway,direction to east,car amount on oneway:"
        <<*numCars<<endl;
    }
    else if(direc==1){
        cout<<getpid()<<"car pass through oneway,direction to west,car amount on oneway:"
        <<*numCars<<endl;
    }
    sleep(4);
    //lock2->open_lock();
}
void OneWay::Quit(int direc){
    lock3->close_lock();
    *numCars-=1;
    if(direc==0){
        cout<<getpid()<<"car leaves oneway,direction to east"<<endl;
    }else if(direc==1){
        cout<<getpid()<<"car leaves oneway,direction to west"<<endl;
    }
    //cout<<*numCars<<endl;
    if(*numCars==0){
        if(direc==0){
            if(*westWait>0){
                condition->Signal(1);
            }
            else if(*eastWait>0){
                condition->Signal(0);
            }
        }
        else if(direc==1){
            if(*eastWait>0){
                condition->Signal(0);
            }
            else if(*westWait>0){
                condition->Signal(1);
            }
        }
    }
    lock3->open_lock();
}
OneWay::~OneWay(){
    delete condition;
}
int main(int argc,char **argv){
    int maxCars;
    int maxSingleDirect;
    cout<<"Please enter total amount of cars:";
    cin>>maxCars;
    cout<<"Please enter the max amount of cars in the same direction:";
    cin>>maxSingleDirect;
    OneWay *oneway=new OneWay(maxCars,maxSingleDirect);
    //build tube, check if enterable,decide the direction to ride into oneway;
    int i;
    int pid[maxCars];
    srand(time(NULL));
    for(i=0;i<maxCars;i++){
        pid[i]=fork();
        //when a new process is running,the random series will reset,
        //so we should decide the direction outside the declaration if();
        int direct;
        direct=rand()%2;//fair decision of direction
        if(pid[i]==0){
            sleep(1);
            //direct=*oneway->sumPassedCars%2;
            oneway->Arrive(direct);
            oneway->Cross(direct);
            oneway->Quit(direct);
            exit(EXIT_SUCCESS);
        }
    }
    for(int i=0;i<maxCars;i++){
        waitpid(pid[i],NULL,0);
    }
    cout<<*(oneway->eastCount)<<" cars to east,"<<*(oneway->westCount)
    <<" cars to west, transportation is running regularly."<<endl;
    delete oneway;
    return EXIT_SUCCESS;
}

makefile:

head=dp.h
srcs=Dp.cpp
objs=Dp.o
opts=-w -g -c
all: Dp
Dp:  $(objs)
 	g++  $(objs)  -o Dp
Dp.o: $(head)  $(srcs)
 	g++  $(opts)  $(srcs)
clean:
 	rm Dp *.o
  • 5
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值