文章目录
- OS_用户层的IO软件@缓冲区@磁盘高速缓存@异步IO
- 用户层的IO软件🎈
- 1.系统调用
- 2.库函数
- 高速缓存与缓冲区
- 磁盘高速媛存(Disk Cache)
- 缓冲区Buffer
- 缓冲的用途
- 设备速度的巨大差异🎈
- 缓冲和缓存的比较
- 联系
- 区别
- 缓冲区的结构
- 缓冲的引入
- 单缓冲区和双缓冲区
- 单缓冲区(SingleBuffer)
- 时序关系
- 小结
- 双缓冲区(DoubleBuffer)
- 缓冲区的共享互斥
- 工作效率的具体推导
- 总结1:
- 总结2:
- 综合例🎈
- 例
- 双buffer的应用
- 循环缓冲
- 缓冲池
- 非阻塞与异步I/O🎈
- 阻塞I/O
- 非阻塞I/O
- 异步系统调用
OS_用户层的IO软件@缓冲区@磁盘高速缓存@异步IO
用户层的IO软件🎈
- 用户层的I/O软件一般而言,大部分的I/O软件都放在操作系统内部,
- 但仍有一小部分在用户层,其中包括与用户程序链接在一起的库函数,以及完全运行于内核之外的假脱机系统等。
1.系统调用
- 一方面,为使诸进程能有条不紊地使用I/O设备,且能保护设备的安全性,不允许运行在用户态的应用进程去直接调用运行在核心态(系统态)的OS过程。
- 但另一方面,应用进程在运行时,又必须取得OS所提供的服务,否则,应用程序几乎无法运行。
- 为了解决此矛盾,OS在用户层中引入了一个中介过程——系统调用,应用程序可以通过它间接调用OS中的I/O过程,对I/O设备进行操作。
- 系统中会有许多系统调用,它们的实现方法是基本相同的。
- 系统调用的执行过程。
- 当应用程序需要执行某种I/O操作时,在应用程序中必须使用相应的系统调用。
- 当OS捕获到应用程序中的该系统调用后,便将CPU的状态从用户态转换到核心态,然后转向操作系统中相应过程,由该过程完成所需的I/O操作。
- 执行完成后,系统又将CPU状态从核心态转换到用户态,返回到应用程序继续执行
- 由OS向用户提供的所有功能,用户进程都必须通过系统调用来获取,
- 或者说,系统调用是应用程序取得OS所有服务的唯一途径。
- 在早期的操作中,系统调用是以汇编语言形式提供的,所以只有在用汇编语言编写的程序中,才能直接使用系统调用,这对用户是非常不方便的,后来在C语言中,首先提供了与系统调用相对应的库函数。
2.库函数
-
在C语言以及UNIX系统中,系统调用(如read)与各系统调用所使用的库函数(如read)之间几乎是一一对应的。
-
而微软定义了一套过程,称为Win32API的应用程序接口(ApplicationProgramInterface),程序员利用它们取得OS服务,该接口与实际的系统调用并不一一对应。
-
用户程序通过调用对应的库函数使用系统调用,这些库函数与调用程序连接在一起,被嵌入在运行时装入内存的二进制程序中。
-
在C语言中提供了多种类型的库函数,对于I/O方面,主要是对文件和设备进行读/写的库函数,以及控制/检查设备状态的库函数。
-
显然这些库函数的集合也应是I/O系统的组成部分。
-
而且我们可以这样来看待内核和库函数之间的关系:内核提供了OS的基本功能,而库函数扩展了OS内核,使用户能方便取得操作系统的服务。
-
在许多现代OS中,系统调用本身已经采用C语言编写,并以函数形式提供,所以在使用C语言编写的用户程序中,可以直接使用这些系统调用。
-
另外,操作系统在用户层中还提供了一些非常有用的程序,如下面将要介绍的假脱机系统,以及在网络传输文件时常使用的守护进程等,它们是运行在内核之外的程序,但它们仍属于I/O系统。
高速缓存与缓冲区
磁盘高速媛存(Disk Cache)
-
操作系统中使用磁盘高速缓存技术来提高磁盘的I/O速度,对访问高速缓存要比访问原始磁盘数据更为高效。
- 例如,正在运行进程的数据既存储在磁盘上,又存储在物理内存上,也被复制到CPU的二级和一级高速缓存中。
- 磁盘高速缓存技术不同于通常意义下的介于CPU与内存之间的小容量高速存储器,
- 而是指利用内存中的存储空间来暂存从磁盘中读出的一系列盘块中的信息。
- 因此,磁盘高速缓存逻辑上属于磁盘,物理上则是驻留在内存中的盘块。
-
高速缓存在内存中分为两种形式:
- 一种是在内存中开辟一个单独的空间作为磁盘高速缓存,大小固定;
- 另一种是把未利用的内存空间作为一个缓冲池(大小显然不固定),供请求分页系统和磁盘I/O时共享。
-
缓存(cache)是保存数据副本的高速内存区域。
- 访问缓存副本比访问原版更加有快。
- 例如,正在运行进程的指令保存在磁盘上,缓存在物理内存上,并再次复制到CPU的次缓存和主缓存。
- 访问缓存副本比访问原版更加有快。
缓冲区Buffer
-
缓冲区(buffer)是一块内存区域,用于保存在两个设备之间或在设备和应用程序之间传输的数据。
-
采用缓冲有三个理由。
缓冲的用途
-
一个用途是,处理数据流的生产者与消费者之间的速度不匹配。
- 例如,假如通过调制解调器正在接收一个文件,并且保存到硬盘。
- 调制解调器大约比硬盘慢一千倍。
- 这样,创建一个缓冲区在内存中,以便累积从调制解调器处接收的字节。
- 当整个数据缓冲区填满时,就可以通过一次操作将缓冲区写到磁盘。
- 由于写入磁盘不是即时的而且调制解调器仍然需要一个空间继续存储额外的输入数据,所以采用两个缓冲区。
- 在调制解调器填满第一个缓冲区后,就请求写入磁盘。
- 接着,调制解调器开始填写第二个缓冲区,
- 而这时第一个缓冲区正被写入磁盘。
- 等到调制解调器写满第二个缓冲区时,第一个缓冲区的磁盘写入也应完成;
- 因此调制解调器可以切换到第一个缓冲区,而磁盘可以写第二个缓冲区。
- 这种双缓冲(doublebuffering)解耦数据的生产者与消费者,因此放松两者之间的时序要求。
-
缓冲的第二种用途是,协调传输大小不一数据的设备。
- 这种不一致在计算机网络中特别常见,缓冲区大量用于消息的分段和重组。
- 在发送端,一个大的消息分成若干小的网络分组。
- 这些网络分组通过网络传输,而接收端将它们放在重组缓冲区内,以便生成完整的源数据映像。
-
缓冲的第三种用途是,支持应用程序I/O的复制语义。(数据版本保持)
- 通过例子可以阐明“复制语义”的含义。
- 假设应用程序有一个数据缓冲区,它希望写到磁盘。
- 它调用系统调用write,提供缓冲区的指针和表示所写字节数量的整数。
- 在系统调用返回后,如果应用程序更改缓冲区的内容,那么会发生什么?
- 采用复制语义(copysemantics),写到磁盘的数据版本保证是应用程序系统调用时的版本,而与应用程序缓冲区的任何后续更改无关。
- 操作系统保证复制语义的一种简单方式是,系统调用write在返回到应用程序之前,复制应用程序缓冲区到内核缓冲区。
- 磁盘写入通过内核缓冲区来执行,以便应用程序缓冲区的后续更改没有影响。
- 内核缓冲区和应用程序数据空间的数据复制在操作系统中很常见,
- 尽管由于干净语义,这个操作引入了这个操作引入了开销
- 通过巧妙使用虚拟内存映射和写时复制页面保护,可以更有效地得到同样的效果。
- 通过例子可以阐明“复制语义”的含义。
设备速度的巨大差异🎈
- 下图列出了典型计算机硬件的设备速度的巨大差异
缓冲和缓存的比较
联系
- 都介于高速设备和低速设备之间
区别
- 缓冲和缓存的区别是,缓冲可以保存数据项的唯一的现有副本,
- 缓存只是提供了一个位于其他地方的数据项的更快存储副本。
区别 | 高速缓存 | 缓冲区 |
---|---|---|
存放数据 | 存放的是低速设备上的某些数据的复制数据,即高速缓存上有的,低速设备上面必 然有 | 存放的是低速设备传递给高速设备的数据(或相反),而这 些数据在低速设备(或高速设备)上却不一定有备份,这些数据再从缓冲区传送到高速设备(或低速设备) |
目的 | 高速缓存存放的是高速设备经常要访问的数据,若高速设备要访问的数据不在高速缓存中,则高速设备就需要访问低速设备 | 高速设备和低速设备的通信都要经过缓冲区,高速设备永远不会直接去访问低速设备 |
-
缓存和缓冲的功能不同
-
但是有时一个内存区域可以用于两个目的
-
例如,
- 为了保留复制语义和有效调度磁盘I/O,操作系统采用内存中的缓冲区来保存磁盘数据、这些缓冲区也用作缓存,以便提高文件的I/O效率;
- 这些文件可被多个程序共享,或者快速地写入和重读。
- 当内核收到文件I/O请求时,内核首先访问缓冲区缓存,以便查看文件区域是否已经在内存中可用。
- 如果是,可以避免或延退物理磁盘I/O。
- 此外,磁盘写入在数秒内会累积到缓冲缓存,以汇集大量传输来允许高效写入调度。
缓冲区的结构
-
在现代操作系统中,几乎所有的I/O设备在与处理机交换数据时都用了缓冲区。
-
缓冲区是一个存储区域,它可以由专门的硬件寄存器组成,但由于硬件的成本较高,容量也较小,一般仅用在对速度要求非常高的场合,如存储器管理中所用的联想存储器;设备控制器中用的数据缓冲区等。
-
在一般情况下,更多的是利用内存作为缓冲区。
- 由内存组成的缓冲区
-
缓冲区管理的主要功能是组织好这些缓冲区,并提供获得和释放缓冲区的手段。
缓冲的引入
- 引入缓冲区的原因有很多,可归结为以下几点:
- (1)缓和CPU与I/O设备间速度不匹配的矛盾。
- 事实上,凡在数据到达速率与其离去速率不同的地方,都可设置缓冲区,以缓和它们之间速率不匹配的矛盾。众所周知,CPU的运算速率远远高于I/O设备的速率,如果没有缓冲区,在输出数据时,必然会由于打印机的速度跟不上,而使CPU停下来等待:然而在计算阶段,打印机又空闲无事。
- 如果在打印机或控制器中设置一缓冲区,用于快速暂存程序的输出数据,以后由打印机“慢慢地”从中取出数据打印,这样,就可提高CPU的工作效率。
- 类似地,在输入设备与CPU之间设置缓冲区,也可使CPU的工作效率得以提高。
- (2)减少对CPU的中断频率,放宽对CPU中断响应时间的限制。
- 在远程通信系统中,如果从远地终端发来的数据仅用一位缓冲来接收,则必须在每收到一位数据时便中断一次CPU
- 这样,对于速率为9.6kb/s的数据通信 9.6 k b / s ≈ 10 k b / s = 1 0 4 b / ( 1 0 3 m s ) = 10 b / m s = 10 b / 1000 u s = 1 b / 100 u s 9.6kb/s\approx10kb/s=10^4b/(10^3ms)=10b/ms=10b/1000us=1b/100us 9.6kb/s≈10kb/s=104b/(103ms)=10b/ms=10b/1000us=1b/100us来说,就意味着其中断CPU的频率也为9.6kb/s,
- 即每100us就要中断CPU一次,而且CPU必须在100us内予以响应,否则缓冲区内的数据将被冲掉。
- 倘若设置一个具有8位的缓冲(移位)寄存器,则可使CPU被中断的频率降低为原来的1/8;
- 缓冲所有位填满的时候发出中断,让cpu取走数据
- 而cpu必须在下一个数据填充进来之前,完成响应,否则会丢失掉一个bit
- 而使用第三种形态(两个8位缓冲寄存器,可以放宽中断响应时限的要求值8倍:
- 当第一个缓冲寄存器满,发送一个中断请求,如果在下一个数据进入缓冲前,cpu未能完成响应,那么第二个8bit寄存器就排上用场,防止数据丢失,如果第二个寄存器的8位都用上可以放宽8倍的cpu中断响应时限)
- 若再设置一个8位寄存器,则又可把CPU对中断的响应时间从100us放宽到800us。
- 类似地,在磁盘控制器和磁带控制器中,都需要配置缓冲寄存器,以减少对CPU的中断频率,放宽对CPU中断响应时间的限制。随着传输速率的提高,需要配置位数更多的寄存器进行缓冲。
- (3)解决数据粒度不匹配的问题。
- 缓冲区可用于解决在生产者和消费者之间交换的数据粒度(数据单元大小)不匹配的问题。
- 例如,生产者所生产的数据粒度比消费者消费的数据粒度小时,生产者进程可以一连生产好几个数据单元的数据,当其总和己达到消费者进程所要求的数据单元大小时,消费者便可从缓冲区中取出消费。反之,如果生产者所生产的数据粒度比消费者消费的数据粒度大时,生产者每次生产的数据消费者可以分几次从缓冲区中取出消费。
- (4)提高CPU和I/O设备之间的并行性。
- 缓冲区的引入可显著地提高CPU和I/O设备间的并行操作程度,提高系统的吞吐量和设备的利用率。
- 例如,在CPU(生产者)和打印机(消费者)之间设置了缓冲区后,生产者在生产了一批数据并将它放入缓冲区后,便可立即去进行下一次的生产。
- 与此同时,消费者可以从缓冲区中取出数据消费,这样便可使CPU与打印机处于并行工作状态。
- 缓冲区的引入可显著地提高CPU和I/O设备间的并行操作程度,提高系统的吞吐量和设备的利用率。
- 在远程通信系统中,如果从远地终端发来的数据仅用一位缓冲来接收,则必须在每收到一位数据时便中断一次CPU
单缓冲区和双缓冲区
- 如果在生产者与消费者之间未设置任何缓冲,生产者与消费者之间在时间上会相互限制。
- 例如,生产者已经完成了数据的生产,但消费者尚未准备好接收,生产者无法把所生产的数据交付给消费者,此时生产者必须暂停等待,直到消费者就绪。
- 如果在生产者与消费者之间设置了一个缓冲区,则生产者无需等待消费者就绪,便可把数据输出到缓冲区。
单缓冲区(SingleBuffer)
- 在单缓冲情况下,每当用户进程发出一I/O请求时,操作系统便在主存中为之分配一缓冲区,
- 在块设备输入时,假定从磁盘把一块数据输入到缓冲区的时间为T(transfer),
- OS将该缓冲区中的数据传送到用户区的时间为M,
- 而CPU对这一块数据处理(计算)的时间为C(calculation)。
时序关系
- 记第i次的IO操作序列位
- S i = ( T i , M i , C i ) = ( T ( i ) , M ( i ) , C ( i ) ) S_i=(T_i,M_i,C_i)=(T(i),M(i),C(i)) Si=(Ti,Mi,Ci)=(T(i),M(i),C(i))
- 第i+1次的IO操作序列为
- S i + 1 = ( T i + 1 , M i + 1 , C i + 1 ) = ( T ( i + 1 ) , M ( i + 1 ) , C ( i + 1 ) ) S_{i+1}=(T_{i+1},M_{i+1},C_{i+1})=(T(i+1),M(i+1),C(i+1)) Si+1=(Ti+1,Mi+1,Ci+1)=(T(i+1),M(i+1),C(i+1))
- T ( i ) , M ( i ) , C ( i ) T(i),M(i),C(i) T(i),M(i),C(i)是不可以相互重叠的
- 但是允许 C ( i ) 和 T ( i + 1 ) C(i)和T(i+1) C(i)和T(i+1)重叠,并且C(i)和T(i+1)可以同时开始
- M(i+1)只能在C(i)接受后开始
- 所以平均情况下,一个操作序列的耗时为
- U=max(C,T)
- V=min(C,T)
- avg= M + U = M + m a x ( C , T ) M+U=M+max(C,T) M+U=M+max(C,T)
- 由于重叠(并行)执行的效果,所有操作序列中在时间轴上的V时间段,被U时间段所覆盖
- 所以不计V的时间段,而只需要计算U的时间段,还有M的时间段
- 这就转换为不重叠的串行执行模型
- 实际上,avg_n= 1 n ( n × ( M + U ) + V ) \frac{1}{n}({n\times{(M+U)}}+V) n1(n×(M+U)+V)
- 当n很大的时候,avg_n ≈ \approx ≈avg=M+U
小结
-
总时间
- 计算总时间的时候,往往要按照 T n = n × ( M + U ) + V T_n=n\times{(M+U)}+V Tn=n×(M+U)+V来计算
- 故可把系统对每一块数据的处理时间表示为
M
a
x
(
C
,
T
)
+
M
Max(C,T)+M
Max(C,T)+M
- 从流水的角度来看(平均情况)(IO块数(任务数) n → ∞ n\to{\infin} n→∞)的情况下
-
在字符设备输入时,缓冲区用于暂存用户输入的一行数据,在输入期间,用户进程被挂起以等待数据输入完毕:在输出时,用户进程将一行数据输入到缓冲区后继续进行处理。
-
当用户进程已有第二行数据输出时,如果第一行数据尚未被提取完毕,则此时用户进程应阻塞。
双缓冲区(DoubleBuffer)
缓冲区的共享互斥
-
由于缓冲区是共享资源,生产者与消费者在使用缓冲区时必须互斥。
-
如果消费者尚未取走缓冲区中的数据,即使生产者又生产出新的数据,也无法将它送入缓冲区,生产者等待。
-
如果为生产者与消费者设置了两个缓冲区,便能解决这一问题。
-
根据单缓冲的特点,CPU在传送时间M内处于空闲状态,由此引入双缓冲。
-
I/O设备输入数据时先装填到缓冲区1,在缓冲区1填满后才开始装填缓冲区2,
-
与此同时处理机可以从缓冲区1中取出数据送入用户进程,当缓冲区1中的数据处理完后,若缓冲区2已填满,则处理机又从缓冲区2中取出数据送入用户进程,而I/O设备又可以装填缓冲区1。
- 注意,必须等缓冲区2充满才能让处理机从缓冲区2取出数据。
-
双缓冲机制提高了处理机和输入设备的并行程度。
-
为了研究双缓冲处理一块数据的用时,我们先规定一种初始状态:
- 工作区是空的,
- 其中一个缓冲区是满的,
- 另外一个缓冲区是空的:
-
记
-
对缓冲区k的第i次的IO操作序列:
- S ( k ) ( i ) = ( T ( k ) ( i ) , M ( k ) ( i ) , C ( k ) ( i ) ) S(k)(i)=(T(k)(i),M(k)(i),C(k)(i)) S(k)(i)=(T(k)(i),M(k)(i),C(k)(i))
- k ∈ s = { 1 , 2 } k\in{s=\{1,2\}} k∈s={1,2},k表示缓冲区编号
- 令 p , q ∈ s , p ≠ q 令p,q\in{s},p\neq{q} 令p,q∈s,p=q
-
T ( k ) ( i ) , M ( k ) ( i ) , C ( k ) ( i ) T(k)(i),M(k)(i),C(k)(i) T(k)(i),M(k)(i),C(k)(i)是不可以相互重叠的
-
但是允许 t 1 = M ( p ) ( i ) + C ( p ) ( i ) 和 t 2 = T ( q ) ( i + 1 ) t_1=M(p)(i)+C(p)(i)和t_2=T(q)(i+1) t1=M(p)(i)+C(p)(i)和t2=T(q)(i+1)可以重叠
-
如果仅仅衡量时间长度,那么 t 1 = M + C , t 2 = T t_1=M+C,t_2=T t1=M+C,t2=T
-
并 且 M ( p ) ( i ) 可 以 和 T ( q ) ( i + 1 ) 同 时 开 始 并且M(p)(i)可以和T(q)(i+1)同时开始 并且M(p)(i)可以和T(q)(i+1)同时开始
-
结果分为两种情况:
- t 1 < t 2 t_1<t_2 t1<t2
- t 2 < t 1 t_2<t_1 t2<t1
- 相等情况随意归入上述一种
-
分析工作时间线示意图得出规律
-
记 U = m a x ( t 1 , t 2 ) 记U=max(t_1,t_2) 记U=max(t1,t2)
-
V = m i n ( t 1 , t 2 ) V=min(t_1,t_2) V=min(t1,t2)
-
T d n = n U d + V d = n ( m a x ( M + C , T ) ) + m i n ( M + C , T ) T_{dn}=nU_d+V_d=n(max(M+C,T))+min(M+C,T) Tdn=nUd+Vd=n(max(M+C,T))+min(M+C,T)
-
a v g = lim n → ∞ 1 n ( n × U + V ) = U + lim n → ∞ 1 n ( V ) = U avg=\lim\limits_{n\to{\infin}}\frac{1}{n}(n\times{U}+V) =U+\lim\limits_{n\to{\infin}}\frac{1}{n}(V)=U avg=n→∞limn1(n×U+V)=U+n→∞limn1(V)=U
-
-
-
工作效率的具体推导
-
我们不妨假设缓冲区1是空的,缓冲区2是满的。
-
我们假设M<T<C+M,
-
缓冲区2开始向工作区W传送数据,M
-
缓冲区1开始冲入数据T,
-
工作区是唯一的
-
2个缓冲区和工作区的大小一致
-
当工作区被缓冲区2中的数据充满数据后,缓冲区2为空,时间为M,
-
然后工作区开始处理数据C,缓冲区1继续冲入数据((T>M),因为此时只有一个I/O设备,所以缓冲区2虽然为空,但不能冲入数据。
- 其中一个缓冲区(Buffer2)出现空档(空闲时间段) τ \tau τ
- θ ∈ ( M , T ) \theta\in(M,T) θ∈(M,T)
- τ 1 = T − θ \tau_1=T-\theta τ1=T−θ
-
τ
2
=
M
+
C
−
T
\tau_2=M+C-T
τ2=M+C−T
- T时刻之后,
- Buffer1则在T时刻刚刚已经充满了
- Buffer2应该可以接受已经空闲了的IO的填充
- T时刻之后,
-
当缓冲区1充满数据后,工作区的数据还未处理完毕,时间为T
-
当工作区W数据处理完毕后,此时工作区W为空,缓冲区1满,缓冲区2为空,
-
达到下一个初始状态,用时C+M
- 这里的初始状态不一定完全和起点一样,但是至少可以确定,缓冲区有一个缓冲区是满的
- 这正情况下,数据转移到工作区和cpu执行工作区数据的计算工作是衔接紧密(不会出现cpu等待缓冲区buffer的情况)
- 结论和前面讨论的一致avg=M+C=Max(M+C,T)
-
我们再来分析T>C+M的情况。
- 缓冲区2开始向工作区传送数据,缓冲区1开始冲入数据,当工作区充满数据并处理完后,用时C+M,
- 但缓冲区1的数据还未充满:当时间为T时,缓冲区1的数据充满,到达下一个初始状态。
-
总结1:
- 双缓冲区处理一块数据的用时为 a v g = U = m a x ( C + M , T ) avg=U=max(C+M,T) avg=U=max(C+M,T)。
-
T
d
n
=
n
U
d
+
V
d
T_{dn}=nU_d+V_d
Tdn=nUd+Vd
- 但是双缓冲区U,V计算公式和单缓冲区的不同:
- 双:(double)
- U d = m a x ( M + C , T ) ) ; V d = m i n ( M + C , T ) U_d=max(M+C,T));V_d=min(M+C,T) Ud=max(M+C,T));Vd=min(M+C,T)
- 双:(double)
- 但是双缓冲区U,V计算公式和单缓冲区的不同:
-
T
s
n
=
n
(
M
+
U
s
)
+
V
s
T_sn=n(M+U_s)+V_s
Tsn=n(M+Us)+Vs
- 单:(single)
- U s = m a x ( C , T ) , V s = m i n ( C , T ) U_s=max(C,T),V_s=min(C,T) Us=max(C,T),Vs=min(C,T)
- 单:(single)
总结2:
- 若M+C<T,则可使块设备连续输入;
- 若C+M>T,则可使CPU不必等待设备输入。
综合例🎈
-
[2011统考真题]某文件占10个磁盘块,现要把该文件的磁盘块逐个读入主存缓冲区,并且送到用户区进行分析,假设一个缓冲区与一个磁盘块大小相同,把一个磁盘块读入缓冲区的时间为100μs,将缓冲区的数据传送到用户区的时间是50μs,CPU对一块数据进行分析的时间为50μs。
-
在单缓冲区和双缓冲区结构下,读入并分析完该文件的时间分别是(B)。
-
A.1500μs,1000μs
-
B.1550μs,1100μs
-
C.1550μs,1550μs
-
D.2000μs,2000μs
-
-
分析
- T=100us
- M=50us
- C=50us
- U=max(T,C)=100us
- V=min(T,C)=50us
- T s n = n × ( M + U ) + V = 10 × 150 + 50 = 1550 u s T_{sn}=n\times (M+U)+V=10\times{150}+50=1550us Tsn=n×(M+U)+V=10×150+50=1550us
- U d = m a x ( M + C , T ) = 100 U_d=max(M+C,T)=100 Ud=max(M+C,T)=100
- V d = m i n ( M + C , T ) = 100 V_d=min(M+C,T)=100 Vd=min(M+C,T)=100
- T d n = n U d + V d = 1100 u s T_{dn}=nU_d+V_d=1100us Tdn=nUd+Vd=1100us
例
- [2013统考真题]设系统缓冲区和用户工作区均采用单缓冲,从外设读入一个数据块到系统缓冲区的时间为100,从系统缓冲区读入一个数据块到用户工作区的时间为5,对用户工作区中的一个数据块进行分析的时间为90(如下图所示)。进程从外设读入并分析2个数据块的最短时间是(300us)。
- T=100
- M=5
- C=90
- U=max(T,C)=100
- V=min(T,C)=90
- T s n = n ( M + U ) + V = 2 ( 5 + 100 ) + 90 = 300 T_sn=n(M+U)+V=2(5+100)+90=300 Tsn=n(M+U)+V=2(5+100)+90=300
- 画个草图也可以搞定
双buffer的应用
- 对于字符设备,若采用行输入方式,则采用双缓冲可使用户在输入第一行后,在CPU执行第一行中的命令的同时,用户可继续向第二缓冲区输入下一行数据。
- 而单缓冲情况下则必须等待一行数据被提取完毕才可输入下一行的数据。
- 若两台机器之间通信仅配置了单缓冲,则它们在任意时刻都只能实现单方向的数据传输。
- 例如,
- 只允许把数据从A机传送到B机,或从B机传送到A机,而绝不允许双方同时向对方发送数据。
- 为了实现双向数据传输,必须在两台机器中都设置两个缓冲区,一个用作发送缓冲区,另一个用作接收缓冲区
循环缓冲
- 包含多个大小相等的缓冲区,每个缓冲区中有一个链接指针指向下一个缓冲区,最后一个缓冲区指针指向第一个缓冲区,多个缓冲区构成一个环形。循环缓冲用于输入输出时,还需要有两个指针in和out。
- 对输入而言,首先要从设备接收数据到缓冲区中,指针指向可以输入数据的第一个空缓冲区;
- 当运行进程需要数据时,从循环缓冲区中取一个装满数据的缓冲区,并从此缓冲区中提取数据,Out指针指向可以提取数据的第一个满缓冲区。输出则正好相反。
缓冲池
- 由多个系统公用的缓冲区组成,缓冲区按其使用状况可以形成三个缓冲区队列:
- 空缓冲队列、
- 输入队列:
- 装满输入数据的缓冲(区)队列
- 输出队列:
- 装满输出数据的缓冲区队列
- 还应具有4种缓冲区:
- 用于收容输入数据的工作缓冲区
- 用于提取输入数据的工作缓冲区
- 用于收容输出数据的工作缓冲区
- 用于提取输出数据的工作缓冲区
- 当输入进程需要输入数据时,便从空缓冲队列的队首摘下一个空缓冲区,把它作为收容输入工作缓冲区,然后把输入数据输入其中,装满后再将它挂到输入队列队尾。
- 当计算进程需要输入数据时,便从输入队列取得一个缓冲区作为提取输入(数据)工作缓冲区,计算进程从中提取数据,数据用完后再将它挂到空缓冲队列尾。
- 当计算进程需要输出数据时,便从空缓冲队列的队首取得一个空缓冲区,作为收容输出工作缓冲区,当其中装满输出数据后,再将它挂到输出队列队尾。
- 当要输出时,由输出进程从输出队列中取得一个装满输出数据的缓冲区,作为提取输出工作缓冲区,当数据提取完后,再将它挂到空缓冲队列的队尾。
- 对于循环缓冲和缓冲池,我们只是定性地介绍它们的机理,而不去定量研究它们平均处理一块数据所需要的时间。
非阻塞与异步I/O🎈
阻塞I/O
- 系统调用接口的另一方面涉及选择阻塞I/O与非阻塞I/O。
- 当应用程序执行阻塞(blocking)系统调用时应用程序的执行就被挂起。
- 应用程序会从操作系统的运行队列移到等待队列。
- 当系统调用完成后,应用程序被移回到运行队列,符合恢复执行。
- 当它恢复执行时,它会收到系统调用的返回值。
- I/O设备执行的物理动作常常是异步的,执行时间也是可变的或不可预计的。
- 然而,大多数操作系统为应用程序接口采用阻塞系统调用,因为阻塞应用代码比非阻塞应用代码更加容易理解。
非阻塞I/O
- 有些用户级进程需要使用非阻塞(nonblocking)I/O。
- 一个例子是用户接口,用来接收键盘和鼠标输入,同时处理数据并显示到屏幕。
- 另一个例子是视频应用程序,用来从磁盘文件上读取帧,同时解压并显示输出到显示器。
- 应用程序开发人员可以交叉I/O与执行的一种方法是,编写多线程应用程序。
- 有些线程可以执行阻塞系统调用,而其他线程继续执行。
- 有的操作系统提供非阻塞I/O系统调用。
- 非阻塞调用不会很长时间停止应用程序的执行。
- 相反,它会很快返回,其返回值表示已经传输了多少字节。
异步系统调用
-
非阻塞系统调用的一种替代方法是异步系统调用。
-
异步调用立即返回,无需等待I/O完成,应用程序继续执行代码。
-
在将来I/O完成时,有以下方式来通知应用程序
- 通过设置应用程序地址空间内的某个变址,
- 或通过触发信号或软件中断
- 或在线性控制流之外执行的回调函数,。
-
非阻塞与异步的系统调用的区别是,
- 非阻塞调用read()立即返回任何可用的数据,读取的数据等于或少于请求的字节数,或为零。
- 异步调用read()要求的传输会完整执行,但是完成是在将来的某个特定时间。
-
One way an application writer can overlap execution with I/O is to writea multithreaded application.
-
Some threads can perform blocking system calls,while others continue executing.
-
Some operating systems provide nonblocking I/O system calls.
-
A nonblocking call does not halt the execution of the application for an extended time.
- Instead, it returns quickly, with a return value thatindicates how many bytes were transferred.
-
An alternative to a nonblocking system call is an asynchronous systemcall.
- An asynchronous call returns immediately, without waiting for the I/O to complete.
- The application continues to execute its code.
- The completion of the I/O at some future time is communicated to the application,
- either through the setting of some variable in the address space of the application
- or through the triggering of a signal
- or software interrupt
- or a call-back routine that is executed outside the linear control flow of the application.
- Thedifference between nonblocking and asynchronous system calls is that a nonblocking read() returns immediately with whatever data are available—the full number of bytes requested, fewer, or none at all.
- An asynchronous read() call requests a transfer that will be performed in its entirety but will complete
at some future time.
-
]
-
在现代操作系统中,经常发生异步活动。
- 通常,它们不会暴露给用户或应用程序,而是包含在操作系统操作中。
- 例如,磁盘和网络I/O。
- 在默认情况下,当应用程序发出网络发送请求或磁盘写入请求时,操作系统记住请求,缓冲I/O,并返回到应用程序。如有可能,为了优化整体系统性能,操作系统完成请求。
- 如果临时发生系统故障,则应用程序会丢失任何途中请求。
- 因此,操作系统通常限制缓冲请求的时间。
- 例如,有些版本的UNIX每隔30秒刷新磁盘缓冲区,每个请求在30秒内会被刷新。
- 应用程序内的数据一致性由内核维护,内核在发出I/O请求到设备之前读取数据,确保尚未写入数据返回给请求读者。
- 注意,多个线程对同一文件执行I/O可能不会收到一致的数据,它取决于内核如何实现I/O。在这种情况下,线程可能需要使用加锁协议。
- 有些I/O请求需要立即执行,这样I/O系统调用通常提供方法,以便指定特定设备的给定请求或I/O应当同步执行。
- 通常,它们不会暴露给用户或应用程序,而是包含在操作系统操作中。
-
非阻塞行为的一个很好的例子是,用于网络套接字的系统调用select。
-
这个系统调用需要一个参数来指定最大等待时间。
-
通过设置为0,应用程序可以轮流检测网络活动而无需阻塞。
-
但是采用select引入额外的开销,因为调用select只检查是否可能进行I/O.
-
对于数据传输,在select()之后,还需要采用某种类型的命令read或write。
-
在Mach中,有这种方法的变种,即阻塞多读调用。
-
通过这一系统调用可以对多个设备指定所需的读取,而且只要一个完成就可返回。
-