问题描述:对于同一个文件,读操作可以同时并行,读写操作互斥,写与写互斥。本质上就是同类进程不互斥异类进程互斥的问题。

全都互斥

最简单的解法:

semaphore lock = 1;
 
Reader(){ // 读者进程
    while(1){
        P(lock);
        读文件;
        V(lock);
    }
}
 
Writer(){ // 写者进程
    while(1){
        P(lock);
        写文件;
        V(lock);
    }
}

问题:读者和读者之间每次也要pv,会卡在p(lock)时,现在需要想办法跳过pv操作。

读优先(写优先同理)

思路:让第一个进程加锁🔒,最后一个进程解锁🔓。这样中间的进程就可以不pv, 直接使用啦。

semaphore lock = 1;
int count = 0; // 记录有多少个在使用
 
Reader(){ // 读者进程
    while(1){
        if(count == 0) // 第一个来的上锁
            P(lock);
        count++;
        读文件;
        count--;
        if(count == 0) // 最后一个走的释放锁
            V(lock);
    }
}
 
Writer(){ // 写者进程
    while(1){
        P(lock);
        写文件;
        V(lock);
    }
}

diff1

然而,count的访问需要互斥,否则数据就会冲突

添加互斥访问代码:

semaphore lock = 1;
mutex count_lock = 1; // 互斥访问变量 count
int count = 0; // 记录有多少个在使用
 
Reader(){ // 读者进程
    while(1){
        p(count_lock);
        if(count == 0) // 第一个来的上锁
            P(lock);
        count++;
        V(count_lock);
        读文件;
        p(count_lock);
        count--;
        if(count == 0) // 最后一个走的释放锁
            V(lock);
        V(count_lock);
    }
}
 
Writer(){ // 写者进程
    while(1){
        P(lock);
        写文件;
        V(lock);
    }
}

diff2

不允许读者或写者饿死

其实就是运行写进程插队执行。

semaphore rw = 1; // 读写锁
semaphore w = 1; // 写锁
mutex count_lock = 1; // 互斥访问变量 count
int count = 0; // 记录有多少个在使用
 
Reader(){ // 读者进程
    while(1){
        P(w);
 
        p(count_lock);
        if(count == 0) // 第一个来的上锁
            P(rw);
        count++;
        V(count_lock);
 
        V(w);
 
        读文件;
        p(count_lock);
        count--;
        if(count == 0) // 最后一个走的释放锁
            V(rw);
        V(count_lock);
    }
}
 
Writer(){ // 写者进程
    while(1){
        P(w);
        P(rw);
        写文件;
        V(rw);
        V(w);
    }
}

image-20231220165139926

这样,当有读进程在执行是来了个写进程,写进程在P(w)成功后会卡在P(rw)上,这时后来的读进程会卡在P(w),直到现有的所有读进程执行完并释放锁。释放后写进程就可以插队成功啦。