OS不做人系列二——读者写者模型,绝对硬核,我保......证

前言:

     (硬核,看过绝对学到!)在上一篇博客不做人系列用了对话的方式,但是访问量低得可怜,所以咋们还是认真的写一篇硬核读者写者模型。如果你要考研的话,操作系统方面大概率会出这种类似的题目,那么一起来学习吧。

     在我们开始学习之前,我们需要知道一些基础的知识:

     一个数据文件或记录可以被多个进程共享,我们把只要求读该文件的进程称为“Reader进程”,其他进程则称为“Writer进程”。允许多个进程同时读一个共享对象,因为该读操作不会使数据文件混乱。但不允许一个Writer进程和其它Reader进程或Writer进程同时访问共享对象。因为这种访问必将引起混乱。所谓“读者-写者(Reader-Writer Problem)问题”是指保证一个Writer进程必须与其它进程互斥地访问共享对象的同步问题。

小思考:

     那么我们要如何实现读者写者模型呢?如果你看过上一篇,那么你肯定会想到要用信号互斥量的知识点,也就是用PV原语来进行限制。当时我们说的是在临界资源前面加P(这里P意味着申请资源,那么记录减一),后面加V(这里V意味着释放资源,记录加一),所以我们也就有了第一种方案。

     这里怕大家忘记,给出PV语言(当然,也可以看上一篇哦,嘻嘻):

P原语wait(s)
--s.count;//表示申请一个资源
if(s.count<0)//表示没有空闲资源;
{
    调用进程进入等待队列s.queue;
    阻塞调用进程;
}
 
 
V原语signal(s)
++s.count;//表示释放一个资源;
if(s.count<=0)//表示有进程处于阻塞状态
{
    从等待队列中取出一个进程P;
    进程P进入就绪队列;
}

 

一、不成熟的方案

     那么上面抛出了问题之后,我们首先给出最简单的方案,直接加PV原语:

P_Reader{//这里我们设置互斥信号量为mutex_Blackboard
***************** 
P(mutex_Blackboard)
    ...    
    从黑板读信息
    ...
V(mutex_Blackboard)
*****************
}


P_Writer{
***************** 
P(mutex_Blackboard)
    ...    
    向黑板写信息
    ...
V(mutex_Blackboard)
*****************
}

优点:

     我们一看,写者和写者之间的确实现了互斥。

缺点:

1、来一个小例子:首先来了一个写者,mutex_Blackboard减一,然后写者开始操作,写者操作完成了。又来了一个写者,继续操作,此时一旁的读者,十分无奈,看!不做人了吧。

     所以,我们要改进这个方法,那么,既然读是可以多个的,所以我们就让读者优先,这些读者高兴了吧,嘻嘻。


二、读者优先方案

     好的,所以我们就有了读者优先的方案,在展示代码之前,我们思考一下。怎么样才可以实现读者优先呢?

......动动脑子,嘻嘻嘻,越思考,越优秀!

     这个时候,你可能会说,既然读者优先的话,那么我们只需要让读者占有这个互斥信号量就好了呀。是的,在读者块上加一个PV原语,进行判断:如果是第一个读者,那么就抢占mutex_Blackboard,如果是第二个,第三个读者,那么我们先不释放我们的mutex_Blackboard,直到最后一个读者要走的时候,我们再释放资源。这个时候写者才能拿到资源,这不就是读者优先了吗?读者多开心啊。

所以,描述如下:

P_Reader{

***************** 
P(mutex_ReaderCount)//给读者加互斥信号量mutex_ReaderCount
    ReaderCount++//进来一个加一
    if(ReaderCount==1)//如果是第一个,那么就负责去和写者强化mutex_Blackboard
    P(mutex_Blackboard)
V(mutex_ReaderCount)

*****************
    ...    
    从黑板读信息
    ...
*****************

P(mutex_ReaderCount)
    ReaderCount--//如果是最后一个,把资源释放了,给写者(写者真惨)
    if(ReaderCount==0)
    V(mutex_Blackboard)
V(mutex_ReaderCount)
*****************

}


P_Writer{
***************** 
P(mutex_Blackboard)
    ...    
    向黑板写信息
    ...
V(mutex_Blackboard)
*****************
}

优点:

     的确读者优先了,解决了上一个问题,多个读者可以一起学习了(嘻嘻嘻)。

缺点:

     来个小例子,来了一个读者,开始操作,来了一个写者,挂起等待,读者走了,又来了一个读者........来了100个读者,写者一直在等待。写者说:“你们真的不是人,不行,我们要公平竞争!!!”。


三、读者写者公平竞争方案

     所以,要公平竞争的话,我们要怎么做呢?

......思考一下,越思考,越优秀啊

     对!聪明的你又发现了,当读者是第一个的时候,它会抢占资源,然后下一个读者来,又继续占有,这不行啊。所以你想起了上一篇博客的记录者没有,那么我们这里在读者和写者抢占mutex_Blackboard的时候加一个信号互斥量,来一个PV原语。

所以,描述如下:

P_Reader{

***************** 
P(mutex_Register)//加了一个记录
P(mutex_ReaderCount)//给读者加互斥信号量mutex_ReaderCount
    ReaderCount++//进来一个加一
    if(ReaderCount==1)//如果是第一个,那么就负责去和写者强化mutex_Blackboard
    P(mutex_Blackboard)
V(mutex_ReaderCount)
V(mutex_Register)
*****************
    ...    
    从黑板读信息
    ...
*****************

P(mutex_ReaderCount)
    ReaderCount--//如果是最后一个,把资源释放了,给写者(写者真惨)
    if(ReaderCount==0)
    V(mutex_Blackboard)
V(mutex_ReaderCount)
*****************

}


P_Writer{
***************** 
P(mutex_Register)
P(mutex_Blackboard)
    ...    
    向黑板写信息
    ...
V(mutex_Blackboard)
v(mutex_Register)
*****************
}

优点:

     第一个读者来了,register--,redercount--,人数加一,判断是第一个,抢了Blackboard,释放regiser,释放redercount,读操作......这个时候,来了一个写者,regiser--,然后发现前面有人,那么就挂起等待。这个时候,又来了一个读者,前一个读者完成了,就叫它的小弟上去插队,读者2上去,进行regiser判断,发现前面有一个等待的,那么不行,读者2只好挂起等待。这个时候写者就获得资源,开始写操作。一切多么的公平啊!

     但是,写者说:“我们不及时更新消息,你们看啥呢???不行,我们要优先"!


四、写者优先方案

     好的,我们要让写者优先,你们想一想,要怎么办?

......动动脑子,嘻嘻嘻,越思考,越优秀!

     是的,是的,你又想到了,没错,就是给读者加之前写者有些的PV判断,但是这样还不够呀,我们要给读者再加一个PV,让他们比写者多一个资源判断,就继续排队呀。哈哈,不做人了!

描述如下:

P_Reader{

***************** 
P(mutex_enhance)//再加一个,嘻嘻
P(mutex_Register)//加了一个记录
P(mutex_ReaderCount)//给读者加互斥信号量mutex_ReaderCount
    ReaderCount++//进来一个加一
    if(ReaderCount==1)//如果是第一个,那么就负责去和写者强化mutex_Blackboard
    P(mutex_Blackboard)
V(mutex_ReaderCount)
V(mutex_Register)
V(mutex_enhance)
*****************
    ...    
    从黑板读信息
    ...
*****************

P(mutex_ReaderCount)
    ReaderCount--//如果是最后一个,把资源释放了,给写者(写者真惨)
    if(ReaderCount==0)
    V(mutex_Blackboard)
V(mutex_ReaderCount)
*****************

}


P_Writer{

***************** 
P(mutex_WriterCount)
    WriterCount++
    if(WriterCount==1)
    P(mutex_Register)
V(mutex_WriterCount)  
******************

P(mutex_Blackboard)
    ...    
    向黑板写信息
    ...
V(mutex_Blackboard)

*****************
P(mutex_WriterCount)
    WriterCount--
    if(WriterCount==0)
    V(mutex_Register)
V(mutex_WriterCount)  
*****************

}

优点:

     那么来一遍,首先来了一个写者,那么进去,写操作ing,来了一个读者,没有register等待。又来了一个写者2,也是没有Blackboard,等待。写者1写完了,交出了资源,这个时候读者想要插队,但是发现自己没有enhance资源,只好继续挂起。而写者2则得到了资源,开始操作了。Oh,写者不做人了呀。

缺点:

    写者不做人,嘻嘻。

五、小小变形demo

      上面我们说了简单的互斥,读者优先,读者写者公平竞争,写者优先,那么看看掌握得怎么样了。

给出一个问题:

     【问题】:读者有两个组别,读者1组合读者2组,读者1组和读者2组不会同时读黑板,但同一组中的读者可以同时读黑板,并会插队。

     所以你会怎么思考呢?小提示(不同时读,那么有互斥,可以同时读,那么可以组内优先)

所以给个参考答案吧:

P_Reader1 {

***************** 
P(mutex_Reader1Count)
    Reader1Count++
    if(Reader1Count==1)
    P(mutex_Blackboard)
V(mutex_Reader1Count)

*****************
    ...    
    从黑板读信息
    ...
*****************

P(mutex_Reader1Count)
    ReaderCount--
    if(Reader1Count==0)
    V(mutex_Blackboard)
V(mutex_Reader1Count)
*****************

}

P_Reader2 {

***************** 
P(mutex_Reader2Count)
    Reader2Count++
    if(Reader2Count==1)
    P(mutex_Blackboard)
V(mutex_Reader2Count)

*****************
    ...    
    从黑板读信息
    ...
*****************

P(mutex_Reader2Count)
    ReaderCount--
    if(Reader2Count==0)
    V(mutex_Blackboard)
V(mutex_Reader2Count)
*****************

}

     真厉害,那么我们在给出一个问题吧:

【问题】:读者有两个组别,读者1组合读者2组,读者1组和读者2组不会同时读黑板,同一组中的读者也不可以同时读黑板,但可以插队。

     给出你的答案吧,下篇不做人系列我会给出参考答案哦,如果不怎么有思路,可以试着转换为上面的读写这问题哦。

总结:

      好的,关于互斥的操作,简单过了一遍吧,那么你肯定会想,有些时候我们会要求写者在读者前面对吧,这个时候就涉及到了同步问题,那么我们下一篇不做人系列见吧,如有误,欢迎指正哦,谢谢。

     预知后事如何,请听下回分解......

发布了123 篇原创文章 · 获赞 234 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_43919400/article/details/105496253