前言:
(硬核,看过绝对学到!)在上一篇博客不做人系列用了对话的方式,但是访问量低得可怜,所以咋们还是认真的写一篇硬核读者写者模型。如果你要考研的话,操作系统方面大概率会出这种类似的题目,那么一起来学习吧。
在我们开始学习之前,我们需要知道一些基础的知识:
一个数据文件或记录可以被多个进程共享,我们把只要求读该文件的进程称为“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组不会同时读黑板,同一组中的读者也不可以同时读黑板,但可以插队。
给出你的答案吧,下篇不做人系列我会给出参考答案哦,如果不怎么有思路,可以试着转换为上面的读写这问题哦。
总结:
好的,关于互斥的操作,简单过了一遍吧,那么你肯定会想,有些时候我们会要求写者在读者前面对吧,这个时候就涉及到了同步问题,那么我们下一篇不做人系列见吧,如有误,欢迎指正哦,谢谢。
预知后事如何,请听下回分解......