最近复习操作系统的时候,老师格外强调了一下第六章输入输出系统里面的一个知识点,是有关缓冲区的,尤其是缓冲池可以与进程同步互斥结合起来考察,感觉有可能考到。在这里总结一下。
引入
缓冲引入已不是第一次看到了,在学习生产者-消费者问题的时候,就使用了一个缓冲数组作为临界资源。如果没有这个缓冲数组,消费者只能等待生产者生产完物品再消费;如果消费者不消费,生产者也没办法再生产物品。
总结一下,引入缓冲区的原因有以下几点(虽然书上有,还是写一下吧,万一出简答题呢〒▽〒):
- 缓和 CPU 与 I/O 设备间速度不匹配的矛盾
不只是 CPU 和 I/O 设备,数据到达和离开速度不一样就可以设置一个缓冲区,让速度快的设备将数据放入缓冲区,尽早释放快设备,提高效率。 - 减少对 CPU 的中断频率
- 解决数据粒度不匹配的问题
数据粒度就是数据单元大小,就像消费者的例子,如果生产者生产的数据粒度大于消费者的消费粒度,消费者可以分几次从缓冲区取出消费 - 提高 CPU 和 I/O 设备之间的并行性
感觉这几点其实都是在说一个事emmm…
缓冲区设置
硬缓冲:由硬件寄存器实现
软缓冲:在内存中开辟一个空间,用作缓冲区
缓冲区管理方式
- 单缓冲区
- 双缓冲区
- 环形缓冲区
- 缓冲池(**)
单缓冲
当一个用户进程发出I/O请求时,OS在主存中为之分配一缓冲区,可以实现预读和滞后写。这有点像管道通信,但是通信数据只有一个数据区那么大,如果该缓冲区中数据尚未被提取完毕,则此时用户进程应该被阻塞,否则缓冲区内容会被覆盖。
块设备输入时,系统对每一整块数据的处理时间=max(C,T)+M。如果无缓冲区,则处理时间为T+C
双缓冲
可以用作双向数据传输,必须在两台机器中都设置两个缓冲区,一个用作发送缓冲区,另一个用作接收缓冲区。
环形缓冲区
1、环形缓冲区的组成
多个缓冲区,每个缓冲区的大小相同。缓冲区类型有:空缓冲区R、满缓冲区G、正在使用缓冲区C
多个指针:Nexti、Nextg、Current
2、环形缓冲区的使用
- nextg:指示下一个应取数据的buf
- nexti:指示下一个空buf.
- Getbuf:
取nextg对应缓冲区提供使用,将Nextg置为空,Nextg=(Nextg+1)Mod N
取Nexti对应缓冲区提供使用,将Nexti置为满,Nexti=(Nexti+1)Mod N - Releasebuf:
若C空,则改为R;
若C满,则改为G;
3、进程之间的同步
-
Nexti 追上Nextg:
表示输入速度>输出速度,全部buf满,这时输入进程阻塞 -
Nextg追上Nexti:
输入速度<输出速度,全部buf空,这时输出进程阻塞。
缓冲池
- 问题:当系统配置较多的设备时,使用专用缓冲区就要消耗大量的内存空间,且其利用率不高。
- 解决:为了提高缓冲区的利用率,目前广泛使用公用缓冲池,池中的缓冲区可供多个进程共享。
1、缓冲池的组成
- 3个队列:
空缓冲队列emq
输入队列inq
输出队列outq - 四个工作缓冲区:
hin:收容输入数据
sin:提取输入数据
hout:收容输出数据
sout:提取输出数据
2、Getbuf过程和Putbuf过程
void Getbuf(unsigned type){
wait(RS(type));
wait(MS(type));
B(number)=Takebuf(type);
signal(MS(type));
}
void Putbuf(type,number){
wait(MS(type));
Addbuf(type,number);
signal(MS(type));
signal(RS(type));
}
- MS(type):用于互斥访问缓冲池队列的互斥信号量
- RS(type):用于保证进程同步使用缓冲区的资源信号量
- Takebuf(type):用于从type所指示的队列的队首摘下一个缓冲
- Addbuf(type,number):用于将由参数number所指示的缓冲区挂在type队列上
- hin:getbuf(emq); 数据装入;putbuf(inq,hin)
- sin:getbuf(inq); 数据提取;putbuf(emq,sin)
- hout:getbuf(emq);数据装入;putbuf(outq, hout)
- sout:getbuf(outq);数据提取;putbuf(emq,sout)
参考书籍:《计算机操作系统》第四版