今天我们来介绍I/O子系统
I/O子系统是我们计算机操作系统当中
负责与外设打交道的部分
那么在这里呢
我们首先会来介绍
I/O子系统里头它的I/O特征
这里主要是说我们在系统里头
可以连接的设备是有很多种的
速度有很大的差异
那么这些各种设备的访问特征
直接影响到我们
用什么样的方式来跟设备进行交互
在了解它的特征之后
我们会来介绍
I/O的结构和它的数据传输
最后两个部分是
我们在这里举了一个实际的例子 磁盘
对于磁盘的I/O来说
我们会又涉及到两个问题
一个是磁盘的调度
这里指的是说我们在磁盘访问的时候
由于磁头有机械的移动
所以这个时间是会很长
所以在这里头呢我们需要
有相应的一些算法来提高它的性能
这就是我们这里的磁盘调度
另外一个呢是磁盘缓存
也就是说我们把磁盘上的数据
读到内存当中来使用
写回去的数据还需要写回到磁盘里头
这读和写呢
我们可以在内存里头加缓存
从而提高它的访问效率
如何来控制这个磁盘缓存
也是我们这里要讨论的问题
首先我们对I/O设备的接口
进行一个分类
在这里头我们大致的分类有这样三类
字符设备 块设备和网络设备
这三类设备呢
各有一些各自的特点
字符设备通常情况下它的速度很慢
比如说在这里举的例子是
串口 键盘和鼠标
而块设备呢通常是我们的存储设备
比如说磁盘 磁带和光驱
而网络设备呢
是计算机系统与外界打交道的
最重要的手段
你比如说在这里头
我们的以太网 802.11无线网 蓝牙等等
这些都算是网络设备
那么这三种不同的设备呢
它的访问是具有不同的特征的
首先第一个字符设备
所谓字符设备呢
它的访问是以字节为基本的访问单位
然后是顺序访问的
比如说像我们的键盘你敲一个键之后
每次你只能敲一个
如果两个在一块的话它是组合的
对于计算机系统来说它也是一个
那这个输入是
一个字节一个字节来进行输出的
像串口它也是两个方向
每个方向也是
一个字节一个字节为单位往外输出的
这时候呢
它的访问通常由get put
这样两个I/O的命令
在这里我们通常把它封装成一个文件
用文件访问的接口和语义
来对这些字符设备进行访问
这是第一类
第二类呢是块设备
块设备它最主要的特征是
底下的访问是以基本的数据块
为最小访问单位的
也就是说读写是以一个数据块为单位
这种访问呢是比较均匀的
它的数据量也是比较大的
那我们在访问的时候呢
通常情况下可以使用文件的接口
我们实际上在前面的文件系统里
就是这样在讨论的
为了提高性能也可以使用原始的I/O接口
也就是说我直接对磁盘上的扇区
进行读写控制
我们也说到第三种方式
我可以把磁盘映射到内存当中
用内存映射文件
来对磁盘上的数据进行访问
第三种呢是网络设备
网络设备它的最主要特征呢
是它的交互是比较复杂的
我们有一门专门的网络原理课程
来讨论这一协议
这个地方就是以格式化的报文交换
是它最主要的特征
为了应对这种特征呢
它的I/O命令是专门的网络报文收发接口
send/receive
然后我们多种不同的网络协议呢
是封装在这个网络接口下面的
以使用不同的协议
跟不同的对象进行交互
这是我们在这儿呢
对设备访问的特征有一个大致的描述
有了这些描述之后
我们更主要的问题是会来讨论
CPU与设备之间的交互
那这种交互关系呢
也就是我们这里说的同步和异步I/O
这张图给出了我们用户的进程
与设备进行I/O操作的时候
它的一个大致的结构
用户发出I/O请求
然后这个请求会送到
操作系统内核当中的设备驱动
设备驱动呢会把它转换成硬件的控制
控制你的硬件进行相应的操作
硬件操作完成之后呢
它会产生中断
由内核当中的中断处理例程进行响应
最后送到设备驱动 然后回到用户态
这是进行I/O的一个过程
这个过程实际上
我们说到的第一种方式是阻塞I/O
也就是说我发出请求到数据回来
中间我进程是要处于等待状态的
一直到有数据回来
这种特征对应过来的
收和发分别是这样的
你在读数据的时候
我把命令发出去之后
进程进入等待状态
一直到完成数据的读出
而如果说是写数据
那么是我发出写请求之后
进程进入等待状态
一直到设备完成数据的写入处理
也就是说如果是磁盘的话
它真实写到磁盘扇区了
那这时候我才结束
这个过程到我们这张图里
就变成是用户的请求
首先通过系统调用到设备驱动
设备驱动会把用户请求转换成
实际的硬件控制命令
下来的时候是绕过中间的中断处理的
中断只是在返回的时候有处理
直接控制硬件进行相应的操作
操作结束之后呢
它会产生中断请求
然后转到设备驱动
最后通过系统调用的返回 到用户态
用户得到相应的结果
这是第一种方式
在这种方式里头呢
进程是需要等待的
等待一定会读到数据
或者一定会把数据完成写
第二种方式是非阻塞I/O
也就是说进程在执行的过程当中
我把命令发出去之后我就不等待
这种不等待呢
转换过来是对于读写操作
把系统调用发出命令之后立即返回
返回的值是你进行成功传送的字节数
读或者写的字节数
这时候你在读写的过程当中呢
有可能什么也没读到 什么也没写进去
返回的值是零 这种情况呢
我们还是在这张图里表示出来
那就是写
然后它就直接返回了
这是第二种方式
第二种方式 它可能读写不成功
或者说读写的数据量
跟我想写出去的数据量不一致
于是我们就有了第三种方式
异步I/O
异步I/O是把阻塞和非阻塞两种方式结合起来
它在读数据的时候是
我把我要做的事情标记好
把缓冲区设好
那这样的话告诉内核然后它就返回了
操作系统内核在完成相应的数据处理
并且把读到的数据放到缓存区之后
它会通知用户
而写呢是反过来
我标记好我的数据在什么地方
操作系统完成写到实际的设备上之后
它会通知用户
这个过程在这张图里表现出来是这样的
我先通过系统调用
把我要写的数据告诉设备驱动
然后设备驱动控制硬件设备进行操作
控制完成之后
我不会去等它结果我直接就返回了
而设备操作完成之后它会通过中断
这时候返回出相应的结果
在这个阶段
驱动里头是会需要等待的
而我的应用程序这一段
是可以干别的事情的
这是我们说到的三种I/O操作的方式