有关进程同步与互斥的经典问题

1生产者消费者问题

1.1使用二元信号量解决无限缓冲区的生产者消费者问题

//使用二元信号量解决无限缓冲区的生产者消费者问题
int count = 0;    //count为缓冲区中的数据项个数
BinSem s = 1, delay = 0;    //s为二元信号量,控制生产者和消费者进入临界区;
                            //delay为二元信号量,处理缓冲区为空的情况;
void producer(){
    while(1){
        produce();
        semWaitB(s);
        append();
        count++;
        if(count==1)semSignalB(delay);    //缓冲区非空,唤醒消费者进程
        semSignalB(s);
    }
}

void consumer(){
    semWaitB(delay);
    while(1){
        semWaitB(s);
        take();
        count--;
        m = count;
        semSignalB(s);
        consume();
        //用到m是因为此时在临界区外,在执行下面一条语句之前count可能已经被更新,导致delay不匹配
        if(m==0)semWaitB(delay);    //缓冲区已空,阻塞消费者进程
    }	
}

1.2使用计数信号量解决无限缓冲区的生产者消费者问题 

//使用计数信号量解决无限缓冲区的生产者消费者问题
sem count = 0;    //count为信号量,值等于缓冲区数据项的个数;
BinSem s = 1;    //s为二元信号量,控制生产者消费者进入临界区
void producer(){
    while(1){
        produce();
        semWaitB(s);
        append();
        //下面两行互换没问题,因为消费者必须在两个信号量上等待
        semSignalB(s);
        semSignal(count);	//缓冲区非空
    }	
}
void consumer(){
    while(1){
        //下面两行互换会死锁,如果缓冲区为空时,消费者进入临界区,会因为缓冲区为空被阻塞
        //但是又没有释放二元信号量s,造成生产者无法进入临界区
        semWaitB(count);	
        semWait(s);
        take();
        semSignalB(s);
        consume();
    }	
}

1.3使用计数信号量解决有限缓冲区的生产者消费者问题

//使用计数信号量解决有限缓冲区的生产者消费者问题
const int sizeofbuffer = 100;
sem count = 0;	//count为信号量,值等于缓冲区数据项的个数;
sem avail = sizeofbuffer;	//avail为信号量,记录空闲空间的数目
BinSem s = 1;	//s为二元信号量,控制生产者消费者进入临界区
void producer(){
    while(1){
        produce();
        //下面两行互换会死锁,如果缓冲区满时,生产者进入临界区,会因为缓冲区满被挂起
        //但是又没有释放二元信号量s,造成消费者无法进入临界区
        semWait(avial);
        semWaitB(s);
        append();
        //下面两行互换没问题,因为消费者必须在两个信号量上等待
        semSignalB(s);
        semSignal(count);	//缓冲区非空
    }	
}
void consumer(){
    while(1){
        //下面两行互换会死锁,如果缓冲区为空时,消费者进入临界区,会因为缓冲区为空被挂起
        //但是又没有释放二元信号量s,造成生产者无法进入临界区
        semWaitB(count);	
        semWait(s);
        take();
        //下面两行互换没问题,因为生产者必须在两个信号量上等待
        semSignalB(s);
        semSignal(avail);    //缓冲区没满
        consume();
    }	
}

1.4使用管程解决有限缓冲区的生产者消费者问题

//使用管程解决有限缓冲区的生产者消费者问题
monitor boundedbuffer;    //创建管程
const int N = 100;
char buffer[N];
int nextin,nextout;    //缓冲区指针
int count;	//缓冲区中数据项的个数
cond notfull,notempty;    //为同步设置的条件变量
void append(char x){
    if(count==N)cwait(notfull);    //缓冲区满,防止溢出
    buffer[nextin]=x;
    nextin = (nextin+1)%N;
    count++;
    csignal(notempty);    //释放任何一个等待的进程
}
void take(){
    if(count==0)cwait(notempty);    //缓冲区空,防止下溢
    x = buffer[nextout];
    nextout = (nextout+1)%N;
    count--;
    csignal(notfull);    //释放任何一个等待的进程
}

cmonitor(){    //管程体
    //缓冲区初始化为空
    nextin = 0;
    nextout = 0;
    count = 0;
}

void producer(){
    char x;
    while(1){
        produce(x);
        append(x);
    }
}
void consumer(){
    char x;
    while(1){
        take(x);
        consume(x);
    }
}

1.5使用消息解决有限缓冲区生产者消费者问题

//使用消息解决有限缓冲区生产者消费者问题
const int capacity = 100;    //缓冲区容量
void producer(){
    message pmsg;
    while(1){
        receive(mayproduce,pmsg);    //收到空消息,可以生产数据
        pmsg = produce();
        send(mayconsume,pmsg);    //发送生产的消息
    }
}

void consumer(){
    message cmsg;
    while(1){
        receive(mayconsume,cmsg);    //收到消息,可以消费数据
        consume(cmsg);
        send(mayproduce,null);    //发送空消息
    }
}

void main(){
    create_mailbox(mayproduce);
    create_mailbox(mayconsume);
    for(int i=0;i<capacity;i++){
        send(mayproduce,null);	//最初mayproduce信箱充满了空消息	
    }
    parbegin(producer,consumer);
}

2读者写者问题

2.1读者优先

//读者写者问题,读者优先
int readcount = 0;    //记录读进程的数目
BinSem x = 1, w = 1;    //x用于控制readcout被正确地更新;w用于写进程与其他进程的互斥
void writer(){
    while(1){
        semWaitB(w);
        write();
        semSignalB(w);
    }	
}
void reader(){
    while(1){
        //来了一个读者
        semWaitB(x);
        readcount++;
        if(readcount==1)semWaitB(w);	//读者进入临界区
        semSignal(x);
        read();
        //走了一个读者
        semWaitB(x);
        readcount--;
        if(readcount==0)semSignal(w);	//读者出临界区
        semSignal(x);
	}	
}

2.2写者优先

//读者写者问题,写者优先
int readcount = 0, writecount = 0;    //读者进程数目和写者进程数目
BinSem x = 1, y = 1, z = 1, w = 1, r = 1;
//x控制readcount的更新,y控制writecount的更新,z防止r上出现长队列
//w控制写进程与其他进程的互斥,r用于当一个写进程准备访问数据时,禁止所有的读进程
void reader(){
    while(1){
        //来了一个读进程
        semWaitB(z);
        semWaitB(r);
        semWaitB(x);
        readcount++;
        if(readcount==1)semWaitB(w);	//禁止写
        semSignalB(x);
        semSignalB(r);
        semSignalB(z);
        read();
        //走了一个读进程
        semWaitB(x);
        readcount--;
        if(readcount==0)semSignalB(w);	//允许写
        semWaitB(x);
    }	
}
void writer(){
    while(1){
        //来了一个写进程
        semWaitB(y);
        writecount++;
        if(writecount==1)semWaitB(r);	//禁止读
        semSignalB(y);
        semWaitB(w);
        write();
        semSignalB(w);
        //走了一个写进程
        semWaitB(y);
        writecount--;
        if(writecount==0)semSignalB(r);	//允许读
        semWaitB(y);
    }	
}

2.3使用消息解决读者写者问题

//使用消息解决读者-写者问题
int count = 100;
void reader(int i){
    message rmsg;
    while(1){
        rmsg = i;
        send(readrequest,rmsg);
        receive(mbox[i],rmsg);
        read();
        rmsg = i;
        send(finished,rmsg);
    }
}
void writer(int j){
    message rmsg;
    while(1){
        rmsg = j;
        send(writerequest,rmsg);
        receive(mbox[j],rmsg);
        write();
        write();
        rmsg = j;
        send(finished,rmsg);
    }
}

void controller(){
    while(1){
        if(count<0){    //没有读进程正在等待
            if(!empty(finished)){
                rceive(finished,msg);
                count++;
            }else if(!empty(writerequest)){
                receive(writerequest,msg);
                writer_id = msg.id;
                count-=100;
            }else if(!empty(readrequest)){
                receive(readquest,msg);
                count--;
                send(msg.id,"OK");
            }
        }
        if(count==0){	//唯一未解决的请求是写请求
            send(writer_id,"OK");
            receive(finished,msg);
            count = 100;
        }
        while(count<0){	//写进程已经发出一条请求:
            receive(finished,msg);
            count++;
        }
    }	
}

3哲学家就餐问题

3.1利用信号量解决哲学家就餐问题

//利用信号量解决哲学家就餐问题
sem fork[5] = {1,1,1,1,1};
sem room = 4;    //一次只允许四个哲学家进入餐厅用餐,故肯定有一个哲学家能拿到两个叉子
void phylosopher(int i){
    while(1){
        think();
        wait(room);
        wait(fork[i]);
        wait(fork[(i+1)%5]); //如果所有哲学家同时先拿起左边的叉子,再拿起右边的叉子,则会死锁,解决方法是加个信号量room
        eat();
        signal(fork[i+1]%5);
        signal(fork[i]);
        signal(room);
    }	
}

3.2利用管程解决哲学家就餐问题

//利用管程解决哲学家就餐问题
monitor dining_controller;
cond ForkReady[5];    //condition variable for synchronization
bool fork[5] = {true};
void get_forks(int pid){
    int left = pid;
    int right = [++pid]%5;	
    if(!fork[left])
        cwait(ForkReady[ready]);
    fork(left) = false;
    if(!fork[right])
        cwait(ForkReady[ready]);
    fork(right) = false;
}

void release_forks(int pid){
    int left = pid;
    int right = [++pid]%5;
    if(empty(fork[left]))    //no one is waiting for this fork
        fork[left] = true;
    else
        csignal(ForkReady[left]);    //awaken a process waiting for this fork
    if(empty(fork[right]))
        fork[right] = true;
    else
        csignal(ForkReady[right]);
}

void phylosopher(int k){
    while(1){
        think();
        get_forks(k);
        eat();
        release_forks(k);
    }
}

猜你喜欢

转载自blog.csdn.net/Lee_01/article/details/82258781