os I/O系统的功能、模型和接口

I/O系统管理的主要对象是I/O设备和相应的设备控制器。其最主要的任务是,完成用户提出的I/O请求,提高I/O速率,以及提高设备的利用率,并能为更高层的进程方便地使用这些设备提供手段

I/O系统的基本功能

为了满足系统和用户的要求,I/O系统应具有下述几方面的基本功能,其中,第一、二方面的功能是为了方便用户使用I/O设备;第三、四方面的功能是用于提高CPU和I/O设备的利用率;第五、六方面的功能是为用户在共享设备时提供方便,以保证系统能有条不紊的运行,当系统发生错误时能及时发现错误,甚至于能自动修正错误

1.隐藏物理设备的细节

I/O设备的类型非常多,且彼此间在多方面都有差异,诸如它们接收和产生数据的速度,传输方向、粒度、数据的表示形式及可靠性等方面。为了对这些千差万别的设备进行控制,通常都为它们配置相应的设备控制器。这是一种硬件设备,其中包含有若干个用于存放控制命令的寄存器和存放参数的寄存器。用户通过这些命令和参数,可以控制外部设备执行所要求的操作。
显然,对于不同的设备,需要有不同的命令和参数。例如,在对磁盘进行操作时,不仅要给出本次是读还是写的命令,还需给出源或目标数据的位置,包括磁盘的盘面号、磁道号和扇区号。由此可见,如果要求程序员或用户编写直接面向这些设备的程序,是极端困难的。因此,I/O系统必须通过对设备加以适当的抽象,以隐藏掉物理设备的实现细节,仅向上层进程提供少量的、抽象的读/写命令,如 read 、 write 等。

2.与设备的无关性

隐藏物理设备的细节,在早期的 OS 中就已实现,它可方便用户对设备的使用。与设备的无关性是在较晚时才实现的,这是在隐藏物理设备细节的基础上实现的。一方面,用户不仅可以使用抽象的I/O命令,还可使用抽象的逻辑设备名来使用设备,例如,当要输出打印时,他只须提供读(或写)的命令(提出对I/O的要求),和提供抽象的逻辑设备名,如/dev/printer ,而不必指明是哪一台打印机;另一方面,也可以有效地提高OS的可移植性和易适应性,对于 OS 本身而言,应允许在不需要将整个操作系统进行重新编译的情况下,增添新的设备驱动程序,以方便新的 I / O 设备的安装。如 Windows 中,系统可以为新 I / O 设备自动安装和寻找驱动程序,从而做到即插即用。

3.提高处理机和I/O设备的利用率

在一般的系统中,许多I/O设备间是相互独立的,能够并行操作,在处理机与设备之间也能并行操作。因此,I/O系统的第三个功能是要尽可能地让处理机和I/O设备并行操作,以提高它们的利用率。为此,一方面要求处理机能快速响应用户的I/O请求,使I/O设备尽快地运行起来;另一方面也应尽量减少在每个I/O设备运行时处理机的干预时间。

4.对I/O设备进行控制

对I/O设备进行控制是驱动程序的功能。
目前对I/O设备有四种控制方式:

  • ①采用轮询的可编程I/O方式;
  • ②采用中断的可编程I/O方式;
  • ③直接存储器访问方式;
  • ④I/O通道方式。

具体应采用何种控制方式,与I/O设备的传输速率、传输的数据单位等因素有关。如打印机、键盘终端等低速设备,由于其传输数据的基本单位是字节(或字),故应采用中断的可编程I/O方式;而对于磁盘、光盘等高速设备,由于其传输数据的基本单位是数据块,故应采用直接存储器访问方式,以提高系统的利用率;而I/O通道方式的引入,使对I/O操作的组织和数据的传输,都能独立进行而无需CPU 的干预。为了方便高层软件和用户,显然I/O软件也应屏蔽掉这种差异,向高层软件提供统一的操作接口。

5.确保对设备的正确共享

从设备的共享属性上,可将系统中的设备分为如下两类:

  • (1)独占设备,进程应互斥地访问这类设备,即系统一旦把这类设备分配给了某进程后,便由该进程独占,直至用完释放。典型的独占设备有打印机、磁带机等。系统在对独占设备进行分配时,还应考虑到分配的安全性。
  • (2)共享设备,是指在一段时间内允许多个进程同时访问的设备。典型的共享设备是磁盘,当有多个进程需对磁盘执行读、写操作时,可以交叉进行,不会影响到读、写的正确性。

6.错误处理

大多数的设备都包括了较多的机械和电气部分,运行时容易出现错误和故障。从处理的角度,可将错误分为临时性错误和持久性错误。对于临时性错误,可通过重试操作来纠正,只有在发生了持久性错误时,才需要向上层报告。例如,在磁盘传输过程中发生错误,系统并不认为磁盘已发生了故障,而是可以重新再传,一直要重传多次后,若仍有错,才认为磁盘发生了故障。由于多数错误是与设备紧密相关的,因此对于错误的处理,应该尽可能在接近硬件的层面上进行,即在低层软件能够解决的错就不向上层报告,因此高层也就不能感知;只有低层软件解决不了的错误才向上层报告,请求高层软件解决。


I/O系统的层次结构和模型

I/O软件涉及的面很宽,向下与硬件有密切关系,向上又与文件系统、虚拟存储器系统和用户直接交互,它们都需要I/O系统来实现I/O操作。为使十分复杂的I/O软件能具有清晰的结构、更好的可移植性和易适应性,目前已普遍采用层次式结构的I/O系统。这是将系统中的设备管理模块分为若干个层次,每一层都是利用其下层提供的服务,完成输入输出功能中的某些子功能,并屏蔽这些功能实现的细节,向高层提供服务。

1. I/O软件的层次结构

通常把I/O软件组织成四个层次,如图6-1所示,各层次及其功能如下,图中的箭头表示I/O的控制流:

  • (1)用户层I/O软件,实现与用户交互的接口,用户可直接调用该层所提供的、与I/O操作有关的库函数对设备进行操作。
  • (2)设备独立性软件,用于实现用户程序与设备驱动器的统一接口、设备命名、设备的保护以及设备的分配与释放等,同时为设备管理和数据传送提供必要的存储空间。
  • (3)设备驱动程序,与硬件直接相关,用于具体实现系统对设备发出的操作指令,驱动I/O设备工作的驱动程序。
  • (4)中断处理程序,用于保存被中断进程的 CPU 环境,转入相应的中断处理程序进行处理,处理完毕再恢复被中断进程的现场后,返回到被中断的进程。

在这里插入图片描述

2. I/O系统中各种模块之间的层次视图

为了能更清晰地描述 I/O系统中主要模块之间的关系,我们进一步介绍 I/O系统中各种 I/O模块之间的层次视图。见图6-2所示。

1)I/O系统的上、下接口
(1) I/O系统接口

它是 I/O系统与上层系统之间的接口,向上层提供对设备进行操作的抽象I/O命令,以方便高层对设备的使用。有不少 OS 在用户层提供了与I/O操作有关的库函数,供用户使用。在上层系统中有文件系统、虚拟存储器系统以及用户进程等。

(2)软件/硬件(RW / HW)接口

下面一个接口是软件/硬件接口,在它的上面是中断处理程序和用于不同设备的设备驱动程序。在它的下面是各种设备的控制器。如 CD-ROM 控制器、硬盘控制器、键盘控制器、打印机控制器、网络控制器等,它们都属于硬件。由于设备种类繁多,故该接口相当复杂。
如图6-2所示,在上、下两个接口之间则是I/O系统
在这里插入图片描述

2)I/O系统的分层

与前面所述的I/O软件组织的层次结构相对应,I/O系统本身也可分为如下三个层次:

  • (1)中断处理程序
    处于I/O系统的底层,直接与硬件进行交互。当有I/O设备发来中断请求信号时,在中断硬件做了初步处理后,便转向中断处理程序。它首先保存被中断进程的 CPU 环境,然后转入相应设备的中断处理程序进行处理,在处理完成后,又恢复被中断进程的 CPU 环境,返回断点继续运行。
  • (2)设备驱动程序
    处于I/O系统的次底层,是进程和设备控制器之间的通信程序,其主要功能是,将上层发来的抽象I/O请求转换为对I/O设备的具体命令和参数,并把它装入到设备控制器中的命令和参数寄存器中,或者相反。由于设备之间的差异很大,每类设备的驱动程序都不相同,故必须由设备制造厂商提供,而不是由 OS 设计者来设计。因此,每当在系统中增加一个新设备时,都需要由安装厂商提供新的驱动程序。
  • (3)设备独立性软件
    现代 OS 中的I/O系统基本上都实现了与设备无关性,也称为与设备无关的软件。其基本含义是:I/O软件独立于具体使用的物理设备。由此带来的最大好处是,提高了I/O系统的可适应性和可扩展性。使它们能应用于许多类型的设备,而且在每次增加新设备或替换老设备时,都不需要对I/O软件进行修改,这样就方便了系统的更新和扩展。设备独立性软件的内容包括设备命名、设备分配、数据缓冲和数据高速缓冲一类软件等。

l/O系统接口

在l/O系统与高层之间的接口中,根据设备类型的不同,又进一步分为若干个接口。在图6-2中示出了块设备接口、流设备接口和网络接口。

1.块设备接口

块设备接口是块设备管理程序与高层之间的接口。该接口反映了大部分磁盘存储器和光盘存储器的本质特征,用于控制该类设备的输入或输出。

(1)块设备

所谓块设备,是指数据的存取和传输都是以数据块为单位的设备。典型的块设备是磁盘。该设备的基本特征是传输速率较高,通常每秒钟为数 M 到数十 MB 。另一特征是可寻址,即能指定数据的输入源地址及输出的目标地址,可随机地读写磁盘中任一块;磁盘设备的I/O常采用 DMA 方式。

(2)隐藏了磁盘的二维结构

块设备接口将磁盘上的所有扇区从0到n -1依次编号, n 是磁盘中的扇区总数。经过这样编号后,就把磁盘的二维结构改变为一种线性序列。在二维结构中,每个扇区的地址需要用磁道号和扇区号来表示。或者说,块设备接口隐藏了磁盘地址是二维结构的情况。

(3)将抽象命令映射为低层操作

块设备接口支持上层发来的对文件或设备的打开、读、写和关闭等抽象命令。该接口将上述命令映射为设备能识别的较低层具体操作。例如,上层发来读磁盘命令时,它先将抽象命令中的逻辑块号转换为磁盘的盘面、磁道和扇区等。
虚拟存储器系统也需要使用块设备接口,因为在进程运行期间,每当它所访问的页面不在内存时便会发生缺页中断,此时就需要利用l/O系统,通过块设备接口从磁盘存储器中将所缺之页面调入内存。

2.流设备接口

流设备接口是流设备管理程序与高层之间的接口。该接口又称为字符设备接口,它反映了大部分字符设备的本质特征,用于控制字符设备的输入或输出。

(1)字符设备

所谓字符设备,是指数据的存取和传输是以字符为单位的设备,如键盘、打印机等。字符设备的基本特征是传输速率较低,通常为每秒几个字节至数千字节。另一特征是不可寻址,即不能指定数据的输入源地址及输出的目标地址。字符设备在输入输出时,常采用中断驱动方式。

(2) get 和 put 操作

由于字符设备是不可寻址的,因而对它只能采取顺序存取方式。通常是为字符设备建立一个字符缓冲区(队列),设备的l/O字符流顺序地进入字符缓冲区(读入),或从字符缓冲区顺序地送出到设备(输出)。用户程序获取或输出字符的方法是采用 get 和 put 操作。

  • get 操作用于从字符缓冲区取得一个字符(到内存),将它返回给调用者。
  • put 操作则用于把一个新字符(从内存)输出到字符缓冲区中,以待送出到设备。
(3) in-control 指令

因字符设备的类型非常多,且差异甚大,为了以统一的方式来处理它们,通常在流设备接口中提供了一种通用的 in - control 指令,在该指令中包含了许多参数,每个参数表示一个与具体设备相关的特定功能。
由于大多数流设备都属于独占设备,必须采取互斥方式实现共享,为此,流设备接口提供了打开和关闭操作。在使用这类设备时,必须先用打开操作来打开设备。如果设备已被打开,则表示它正被其它进程使用

3.网络通信接口

在现代 OS 中,都提供了面向网络的功能。但首先还需要通过某种方式把计算机连接到网络上。同时操作系统也必须提供相应的网络软件和网络通信接口,使计算机能通过网络与网络上的其它计算机进行通信或上网浏览。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
假设我们有一个需求,需要从多个URL地址下载图片并保存到本地。在这种情况下,可以使用多线程和异步I/O来实现高效的下载。 首先,我们可以使用多线程来同时下载多个图片。每个线程都负责下载一个图片,并将其保存到本地。这样可以提高下载效率。以下是使用Python的线程池实现的示例代码: ```python import requests import os from concurrent.futures import ThreadPoolExecutor def download_image(url): response = requests.get(url) filename = os.path.basename(url) with open(filename, 'wb') as f: f.write(response.content) urls = ['http://example.com/image1.jpg', 'http://example.com/image2.jpg', 'http://example.com/image3.jpg'] with ThreadPoolExecutor(max_workers=3) as executor: executor.map(download_image, urls) ``` 上述代码中,我们使用了`ThreadPoolExecutor`来创建一个包含三个线程的线程池。然后,我们使用`executor.map`方法来将下载函数`download_image`和URL列表`urls`传递给线程池进行执行。 但是,在上述代码中,每个线程在下载图片时会阻塞,直到下载任务完成。这可能会导致程序在下载大量图片时变得很慢。因此,我们可以使用异步I/O来避免这种情况。 以下是使用Python的异步I/O库`asyncio`实现的示例代码: ```python import asyncio import aiohttp import os async def download_image(url): async with aiohttp.ClientSession() as session: async with session.get(url) as response: filename = os.path.basename(url) with open(filename, 'wb') as f: while True: chunk = await response.content.read(1024) if not chunk: break f.write(chunk) urls = ['http://example.com/image1.jpg', 'http://example.com/image2.jpg', 'http://example.com/image3.jpg'] loop = asyncio.get_event_loop() tasks = [download_image(url) for url in urls] loop.run_until_complete(asyncio.gather(*tasks)) ``` 在上述代码中,我们使用`asyncio`和`aiohttp`库来创建异步下载函数`download_image`。我们使用`aiohttp.ClientSession`对象来发起HTTP请求,并使用异步循环读取响应内容。 然后,我们使用异步循环`asyncio.get_event_loop()`来运行异步任务。我们使用`asyncio.gather`方法来并发运行所有下载任务,并等待它们完成。这样,我们就可以高效地下载多个图片了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Alkali!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值