OS记录型信号量-读者写者问题

本文介绍了如何使用记录型信号量解决经典的读者写者问题。通过分析wait()和signal()操作,阐述了初始版本的读者写者问题实现,详细解释了不同场景下信号量值的变化,揭示了此版本对写进程的不公平性。文章以代码形式展示了读进程和写进程的实现,并在最后提出了问题的公平解决方案。
摘要由CSDN通过智能技术生成

dtitle: OS记录型信号量-读者写者问题
date: 2021-04-09 19:06:16
tags: [信号量机制, OS, 读者写者问题, 记录型信号量]
categories: OS


利用记录型信号量实现读者写者问题

写在最前

最近对 OS 这门课着了迷,hhh,拿起课本就是硬啃

用了一段时间领悟了记录型信号量的几个版本

这是对记录型信号量的一个应用,那么 pv操作( 即wait()和signal() )的具体代码描述 肯定是要烂熟于心的

在这里我就不写书上那么详细了

在这里我唠叨几句,pv操作虽然简简单单的这几行代码,但是非常具有思考性,很多细节只有自己想通了,才能将pv操作“玩弄于鼓掌之上”

改篇详细介绍一下pv操作 和 里面值得思考的细节


wait(S) {
    S->value--;
    if (S->value < 0) 
        block(S->list);
}


signal(S) {
    S->value++;
    if (S->value <= 0)
        signal(S->list);
}

初始版本

为什么叫初始版本呢? 因为它不公平,对读者友好,对写者十分不友好

我们知道读者写者问题中 读读操作是可以同时进行的,唯独写操作不可以与任何操作同时进行

可以进行的操作 单独读 多个同时读 单独写 ;同时读写 和 多个同时写 是不允许的

在这个版本中只有当所有的读者都不再占用文件的时候 写进程才有机会访问文件,光说没什么卵用

下面分析代码,细致地了解到底是怎么个情况,我会将分析对应地写到注释里

着重分析初始版本,因为后面实现读者写者公平的版本 仅仅是对它的一个改良

代码


//  readcount 表示当前有几个读进程正在读文件
int readcount = 0;
// rmutex 用于实现 读读进程 之间的互斥,保护readcount, 防止多个读进程同时访问/修改 readcount
// wmutext 用于实现 读写、写写之间的互斥,总之,一句话,用于实现某一个写进程和其它所有进程的互斥
semaphore rmutex = 1, wmutex = 1;

// 读进程
void Reader() {
    do {
        // 占用 readcount
        // 可以理解为 给readcount "上锁"
        wait(rmutex);
        /* 
        当readcount == 0时,  说明 这个文件可能正在被写进程访问 或者是这个文件在此之前一直处于闲置
        状态且写进程也无意争抢该文件,也有可能 于此同时写进程也想要访问这个文件, 两者将争夺该文件。
        因此必须加上一个wait语句来保证某一个写进程和其它任意进程的互斥。
        
        下面分析一下 当readcount == 0时, 这个进程执行wait语句之后可能的结果
        我将结果分为两个大项,四个小项 			
        - 抢到了文件(在抢的一瞬间文件空闲) 
        	①文件空闲 且执行wait语句前没有写进程和它抢,它肯定是顺利地得到了文件。
                wmutex值的变化:
                 	wmutex 在wait语句执行前的值为 1 执行之后为 0  
                之后若再有写进程想要访问文件:
                    <1>若在signal(wmutex)语句执行之前 有一个写进程再想通过wait(mutex)来获得文件,
                    那么结果只能是 wmutex 值变为 -1 ,这个写进程被阻塞 进入阻塞队列,等待所有读进程
                    都读完之后,readcount变为0 ,执行signal(wmutex)语句,才会去唤醒这个写进程
                    (在此情况下,这个写进程在阻塞队列中必定处于队头),
                    顺带着说了 这也是对写进程的不公平之处。
                    <2>若又有一个读进程想要访问文件,请看第50-51行注释
        

   	    	②文件空闲 但于此同时有一个写进程也想通过wait语句争抢文件 对文件"上锁",
       		但是它先于写进程一步抢到了。
        		wmutex值的变化 以及之后再有进程想要访问文件的变化同上述第一条
        - 没有抢到文件(在抢到之前,文件已经被写进程占了)
        	①文件不空闲 有一个写进程一直都在使用着文件。
                wmutex 在wait执行前的值为m,(m <= 0), 执行后为 m-1, 
                为什么说wmutex原来值为一个<=0的数呢?
                在这里又要分两种情况,在写进程开始写文件之后,这个读进程想要读文件之前的期间:
                    1. 没有其它进程想要访问文件,那么阻塞队列一定是空的,wmutex 值为0
                    2. 有其它的n个进程曾想要访问文件,结果肯定是它们都进入了阻塞队列,
                    wmutex值为 -n == m 
        	②文件空闲 但同时,写进程也想通过wait语句争抢文件 对文件"上锁",
        	写进程抢先一步,得到了文件。
                wmutex 在wait语句执行之前的值为 0, 之后值为 -1 
        */
        
        /*
        	当readcount != 0时, 说明现在有读进程正在读文件,并且第一个执行读操作的进程已经针对
        	写进程上了锁,因此直接令readcount++, 然后进行读操作,读完以后将readcount再减一
        */
        /*
        	以上 其实我已经把整个的思路都给讲了,并且交代了为什么会对写进程不公平
        	还有几种简单情况我没有提的就是 上来就是写进程抢到了文件,在第37行注释中所述情况
        	也是把这个情况给包括了
        */
        /*
        	像进程同步互斥、带pv操作的这种这种联系性很大的代码 
        	真的不能说我要讲就只讲这一段 它们之间紧密联系
        	单独地理解一段代码很难领略到实质,我也是讲着讲着第一段就把整个的都给说出来了hhhh
        	也算是给广大后来者提供一种学习的方式吧 要善于整体感知
        */
        
        if (readcount == 0) wait(wmutex);
        readcount++;
        // "释放" readcount的锁 
        signal(rmutex);
        ...
        perform read operation;
        ...
        wait(rmutex);
        readcount--;
        if (readcount == 0) signal(wmutex);
        signal(rmutex);
    }while(TRUE);
}

// 写进程
void Writer() {
    do {
        wait(wmutex);
        perform write operation;
        signal(wmutex);
    } while(TRUE);
}

// 程序入口
void main() {
    cobegin
        Reader();  Writer();
    coend
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值