======第五章设备管理======(1)https://developer.aliyun.com/article/1415856
5.2.4 I/O 通道控制方式
- I/O 通道控制方式的引入
虽然 DMA 方式比起中断方式来已经显著地减少了 CPU 的干预,即已由以字(节)为单位的干预减少到以数据块为单位的干预,但 CPU 每发出一条 I/O 指令,也只能去读(或写) 一个连续的数据块。而当我们需要一次去读多个数据块且将它们分别传送到不同的内存区域,或者相反时,则须由 CPU 分别发出多条 I/O 指令及进行多次中断处理才能完成。
I/O 通道方式是 DMA 方式的发展,它可进一步减少 CPU 的干预,即把对一个数据块的 读(或写)为单位的干预减少为对一组数据块的读(或写)及有关的控制和管理为单位的干预。 同时,又可实现 CPU、通道和 I/O 设备三者的并行操作,从而更有效地提高整个系统的资源利用率。例如,当 CPU 要完成一组相关的读(或写)操作及有关控制时,只需向 I/O 通道 发送一条 I/O 指令,以给出其所要执行的通道程序的首址和要访问的 I/O 设备,通道接到该 指令后,通过执行通道程序便可完成 CPU 指定的 I/O 任务。
通道程序
通道是通过执行通道程序,并与设备控制器共同实现对 I/O 设备的控制的。通道程序是由一系列通道指令(或称为通道命令)所构成的。通道指令与一般的机器指令不同,在它的每条指令中都包含下列诸信息:
(1) 操作码。操作码规定了指令所执行的操作,如读、写、控制等操作。
(2) 内存地址。内存地址标明字符送入内存(读操作)和从内存取出(写操作)时的内存 首址。
(3) 计数。该信息表示本条指令所要读(或写)数据的字节数。
(4) 通道程序结束位 P。该位用于表示通道程序是否结束。P=1 表示本条指令是通道程 序的最后一条指令。
(5) 记录结束标志 R。R=0 表示本通道指令与下一条指令所处理的数据是同属于一个记 录;R=1 表示这是处理某记录的最后一条指令。
下面示出了一个由六条通道指令所构成的简单的通道程序。该程序的功能是将内存中 不同地址的数据写成多个记录。其中,前三条指令是分别将 813~892 单元中的 80个字符 和 1034~1173 单元中的 140 个字符及 5830~5889 单元中的 60 个字符写成一个记录;第 4 条指令是单独写一个具有 300 个字符的记录;第 5、6 条指令共写含 500 个字符的记录。
5.3 缓冲管理
5.3.1 缓冲的引入
在设备管理中,引入缓冲区的主要原因可归结为以下几点:、
(1) 缓和 CPU 与 I/O 设备间速度不匹配的矛盾。事实上,凡在数据到达速率与其离去 速率不同的地方,都可设置缓冲区,以缓和它们之间速率不匹配的矛盾。众所周知,CPU 的运算速率远远高于 I/O 设备的速率,如果没有缓冲区,则在输出数据时,必然会由于打印 机的速度跟不上而使 CPU 停下来等待;然而在计算阶段,打印机又空闲无事。显然,如果 在打印机或控制器中设置一缓冲区,用于快速暂存程序的输出数据,以后由打印机“慢慢 地”从中取出数据打印,这样,就可提高 CPU 的工作效率。类似地,在输入设备与 CPU 之 间也设置缓冲区,也可使 CPU 的工作效率得以提高。
(2) 减少对 CPU 的中断频率,放宽对 CPU 中断响应时间的限制。在远程通信系统中, 如果从远地终端发来的数据仅用一位缓冲来接收,如图 5-10(a)所示,则必须在每收到一位 数据时便中断一次 CPU,这样,对于速率为 9.6 Kb/s 的数据通信来说,就意味着其中断 CPU 的频率也为 9.6 Kb/s,即每 100 μs 就要中断 CPU 一次,而且 CPU 必须在 100 μs 内予以响应, 否则缓冲区内的数据将被冲掉。倘若设置一个具有 8 位的缓冲(移位)寄存器,如图 5-10(b) 所示,则可使 CPU 被中断的频率降低为原来的 1/8;若再设置一个 8 位寄存器,如图 5-10© 所示,则又可把 CPU 对中断的响应时间放宽到 800 μs。
(3) 提高 CPU 和 I/O 设备之间的并行性。缓冲的引入可显著地提高 CPU 和 I/O 设备间 的并行操作程度,提高系统的吞吐量和设备的利用率。例如,在 CPU 和打印机之间设置了 缓冲区后,便可使 CPU 与打印机并行工作。
5.3.2 单缓冲和双缓冲
- 单缓冲
在单缓冲情况下,每当用户进程发出一 I/O 请求时,操作系统便在主存中为之分配一 缓冲区,如图 5-11 所示。在块设备输入时,假定从磁盘把一块数据输入到缓冲区的时间 为 T,操作系统将该缓冲区中的数据传送到用户区的时间为 M,而 CPU 对这一块数据处 理(计算)的时间为 C。由于 T 和 C 是可以并行的(见图 5-11),当 T>C 时,系统对每一块 数据的处理时间为 M+T, 反之则为 M+C, 故可把系统对每一块数据的处理时间表示为 Max(C,T)+M。
在字符设备输入时,缓冲区用于暂存用户输入的一行数据,在输入期间,用户进程被 挂起以等待数据输入完毕;在输出时,用户进程将一行数据输入到缓冲区后,继续进行处 理。当用户进程已有第二行数据输出时,如果第一行数据尚未被提取完毕,则此时用户进 程应阻塞。
双缓冲
为了加快输入和输出速度, 提高设备利用率, 人们又引入了双缓冲区机制,也称为 缓冲对换(Buffer Swapping)。在设备输入时,先将数据送入第一缓冲区,装满后便转向第 二缓冲区。此时操作系统可以从第一缓冲区中移出数据,并送入用户进程(见图 5-12)。接 着由 CPU 对数据进行计算。在双缓冲时, 系统处理一块数据的时间可以粗略地认为是 Max(C,T)。如果 CT,则可使 CPU 不必等待设备输入。 对于字符设备,若采用行输入方式,则采用双缓冲通常能消除用户的等待时间,即用户在 输入完第一行之后,在 CPU 执行第一行中的命令时,用户可继续向第二缓冲区输入下一行 数据。
如果我们在实现两台机器之间的通信时,仅为它们配置了单缓冲,如图 5-13(a)所示, 那么,它们之间在任一时刻都只能实现单方向的数据传输。例如,只允许把数据从 A 机传 送到 B 机,或者从 B 机传送到 A 机,而绝不允许双方同时向对方发送数据。为了实现双向 数据传输,必须在两台机器中都设置两个缓冲区,一个用作发送缓冲区,另一个用作接收 缓冲区,如图 5-13(b)所示。
5.3.3 循环缓冲
当输入与输出或生产者与消费者的速度基本相匹配时,采用双缓冲能获得较好的效果, 可使生产者和消费者基本上能并行操作。但若两者的速度相差甚远,双缓冲的效果则不够理想,不过可以随着缓冲区数量的增加,使情况有所改善。因此,又引入了多缓冲机制。 可将多个缓冲组织成循环缓冲形式。对于用作输入的循环缓冲,通常是提供给输入进程或 计算进程使用,输入进程不断向空缓冲区输入数据,而计算进程则从中提取数据进行计算。
循环缓冲的组成
(1) 多个缓冲区。在循环缓冲中包括多个缓冲区,其每个缓冲区的大小相同。作为输入 的多缓冲区可分为三种类型:用于装输入数据的空缓冲区 R、已装满数据的缓冲区 G 以及 计算进程正在使用的现行工作缓冲区 C,如图 5-14 所示。
(2) 多个指针。作为输入的缓冲区可设置三个指针:用于指示计算进程下一个可用缓冲 区 G 的指针 Nextg、指示输入进程下次可用的空缓冲区 R 的指针 Nexti,以及用于指示计算 进程正在使用的缓冲区 C 的指针 Current。
循环缓冲去的使用
计算进程和输入进程可利用下述两个过程来使用循环缓冲区。
(1) Getbuf 过程。当计算进程要使用缓冲区中的数据时,可调用 Getbuf 过程。该过程 将由指针 Nextg 所指示的缓冲区提供给进程使用,相应地,须把它改为现行工作缓冲区, 并令 Current 指针指向该缓冲区的第一个单元,同时将 Nextg 移向下一个 G 缓冲区。类似地, 每当输入进程要使用空缓冲区来装入数据时,也调用 Getbuf 过程,由该过程将指针 Nexti 所指示的缓冲区提供给输入进程使用,同时将 Nexti 指针移向下一个 R 缓冲区。
(2) Releasebuf 过程。当计算进程把 C 缓冲区中的数据提取完毕时,便调用 Releasebuf 过程,将缓冲区 C 释放。此时,把该缓冲区由当前(现行)工作缓冲区 C 改为空缓冲区 R。类 似地,当输入进程把缓冲区装满时,也应调用 Releasebuf 过程,将该缓冲区释放,并改为 G 缓冲区。
进程同步
使用输入循环缓冲,可使输入进程和计算进程并行执行。相应地,指针 Nexti 和指针 Nextg 将不断地沿着顺时针方向移动,这样就可能出现下述两种情况:
(1) Nexti 指针追赶上 Nextg 指针。这意味着输入进程输入数据的速度大于计算进程处理数据的速度,已把全部可用的空缓冲区装满,再无缓冲区可用。此时,输入进程应阻塞, 直到计算进程把某个缓冲区中的数据全部提取完,使之成为空缓冲区 R,并调用 Releasebuf 过程将它释放时,才将输入进程唤醒。这种情况被称为系统受计算限制。
(2) Nextg 指针追赶上 Nexti 指针。这意味着输入数据的速度低于计算进程处理数据的速度,使全部装有输入数据的缓冲区都被抽空,再无装有数据的缓冲区供计算进程提取数 据。这时,计算进程只能阻塞,直至输入进程又装满某个缓冲区,并调用 Releasebuf 过程 将它释放时,才去唤醒计算进程。这种情况被称为系统受 I/O 限制。
5.3.4 缓冲池
缓冲池的组成
对于既可用于输入又可用于输出的公用缓冲池, 其中至少应含有以下三种类型的缓冲区:
① 空(闲)缓冲区;
② 装满输入数据的缓冲区;
③ 装满输出数据的缓冲区。
为了管理上的方便,可将相同类型的缓冲区链成一个队列,于是可形成以下三个队列:
(1) 空缓冲队列 emq。这是由空缓冲区所链成的队列。其队首指针 F(emq)和队尾指针 L(emq)分别指向该队列的首缓冲区和尾缓冲区。
(2) 输入队列 inq。这是由装满输入数据的缓冲区所链成的队列。其队首指针 F(inq)和 队尾指针 L(inq)分别指向该队列的首缓冲区和尾缓冲区。
(3) 输出队列 outq。这是由装满输出数据的缓冲区所链成的队列。其队首指针 F(outq)和队尾指针 L(outq)分别指向该队列的首缓冲区和尾缓冲区。
除了上述三个队列外,还应具有四种工作缓冲区:
① 用于收容输入数据的工作缓冲区;
② 用于提取输入数据的工作缓冲区;
③ 用于收容输出数据的工作缓冲区;④ 用于提取输 出数据的工作缓冲区。
Getbuf 过程和 Putbuf 过程
在“数据结构”课程中,曾介绍过队列和对队列进行操作的两个过程,它们是:
(1) Addbuf(type,number)过程。该过程用于将由参数 number 所指示的缓冲区 B 挂在 type 队列上。
(2) Takebuf(type)过程。该过程用于从 type 所指示的队列的队首摘下一个缓冲区。 这两个过程能否用于对缓冲池中的队列进行操作呢?答案是否定的。因为缓冲池中的 队列本身是临界资源,多个进程在访问一个队列时,既应互斥,又须同步。为此,需要对 这两个过程加以改造,以形成可用于对缓冲池中的队列进行操作的 Getbuf 和 Putbuf 过程。 为使诸进程能互斥地访问缓冲池队列,可为每一队列设置一个互斥信号量 MS(type)。 此外, 为了保证诸进程同步地使用缓冲区, 又为每个缓冲队列设置了一个资源信号量 RS(type)。既可实现互斥又可保证同步的 Getbuf 过程和 Putbuf 过程描述如下:
Procedure Getbuf(type) begin Wait(RS(type)); Wait(MS(type)); B(number):=Takebuf(type); Signal(MS(type)); end Procedure Putbuf(type, number) begin Wait(MS(type)); Addbuf(type, number); Signal(MS(type)); Signal(RS(type)); end
- 缓冲区的工作方式
缓冲区可以工作在收容输入、提取输入、收容输出和提取输出四种工作方式下,如图 5-15 所示。
(1) 收容输入。在输入进程需要输入数据时,便调用 Getbuf(emq)过程,从空缓冲队列 emq 的队首摘下一空缓冲区,把它作为收容输入工作缓冲区 hin。然后,把数据输入其中, 装满后再调用 Putbuf(inq,hin)过程,将该缓冲区挂在输入队列 inq 上。
(2) 提取输入。当计算进程需要输入数据时,调用 Getbuf(inq)过程,从输入队列 inq 的 队首取得一个缓冲区,作为提取输入工作缓冲区(sin),计算进程从中提取数据。计算进程用 完该数据后,再调用 Putbuf(emq,sin)过程,将该缓冲区挂到空缓冲队列 emq 上。
(3) 收容输出。当计算进程需要输出时,调用 Getbuf(emq)过程从空缓冲队列 emq 的队 首取得一个空缓冲区,作为收容输出工作缓冲区 hout。当其中装满输出数据后,又调用 Putbuf(outq,hout)过程,将该缓冲区挂在 outq 末尾。
(4) 提取输出。由输出进程调用 Getbuf(outq)过程,从输出队列的队首取得一装满输出 数据的缓冲区,作为提取输出工作缓冲区 sout。在数据提取完后,再调用 Putbuf(emq,sout) 过程,将该缓冲区挂在空缓冲队列末尾。
======第五章设备管理======(3)https://developer.aliyun.com/article/1415859?spm=a2c6h.13148508.setting.27.16254f0exsfwiz