自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

說了這么多次 I/O,可你知道其中的原理么

系統(tǒng) Linux
現(xiàn)在讓我們轉(zhuǎn)向?qū)?I/O 軟件的研究,I/O 軟件設(shè)計(jì)一個(gè)很重要的目標(biāo)就是設(shè)備獨(dú)立性(device independence)。啥意思呢?這意味著我們能夠編寫訪問任何設(shè)備的應(yīng)用程序,而不用事先指定特定的設(shè)備。

本文轉(zhuǎn)載自微信公眾號(hào)「****」,轉(zhuǎn)載本文請(qǐng)聯(lián)系****公眾號(hào)。

[[328690]]

1.IO 軟件原理

I/O 軟件目標(biāo)

設(shè)備獨(dú)立性

現(xiàn)在讓我們轉(zhuǎn)向?qū)?I/O 軟件的研究,I/O 軟件設(shè)計(jì)一個(gè)很重要的目標(biāo)就是設(shè)備獨(dú)立性(device independence)。啥意思呢?這意味著我們能夠編寫訪問任何設(shè)備的應(yīng)用程序,而不用事先指定特定的設(shè)備。比如你編寫了一個(gè)能夠從設(shè)備讀入文件的應(yīng)用程序,那么這個(gè)應(yīng)用程序可以從硬盤、DVD 或者 USB 進(jìn)行讀入,不必再為每個(gè)設(shè)備定制應(yīng)用程序。這其實(shí)就體現(xiàn)了設(shè)備獨(dú)立性的概念。

 

再比如說你可以輸入一條下面的指令

  1. sort 輸入 輸出 

那么上面這個(gè) 輸入 就可以接收來(lái)自任意類型的磁盤或者鍵盤,并且 輸出 可以寫入到任意類型的磁盤或者屏幕。

 

計(jì)算機(jī)操作系統(tǒng)是這些硬件的媒介,因?yàn)椴煌布鼈兊闹噶钚蛄胁煌?,所以需要操作系統(tǒng)來(lái)做指令間的轉(zhuǎn)換。

與設(shè)備獨(dú)立性密切相關(guān)的一個(gè)指標(biāo)就是統(tǒng)一命名(uniform naming)。設(shè)備的代號(hào)應(yīng)該是一個(gè)整數(shù)或者是字符串,它們不應(yīng)該依賴于具體的設(shè)備。在 UNIX 中,所有的磁盤都能夠被集成到文件系統(tǒng)中,所以用戶不用記住每個(gè)設(shè)備的具體名稱,直接記住對(duì)應(yīng)的路徑即可,如果路徑記不住,也可以通過 ls 等指令找到具體的集成位置。舉個(gè)例子來(lái)說,比如一個(gè) USB 磁盤被掛載到了 /usr/cxuan/backup 下,那么你把文件復(fù)制到 /usr/cxuan/backup/device 下,就相當(dāng)于是把文件復(fù)制到了磁盤中,通過這種方式,實(shí)現(xiàn)了向任何磁盤寫入文件都相當(dāng)于是向指定的路徑輸出文件。

錯(cuò)誤處理

除了設(shè)備獨(dú)立性外,I/O 軟件實(shí)現(xiàn)的第二個(gè)重要的目標(biāo)就是錯(cuò)誤處理(error handling)。通常情況下來(lái)說,錯(cuò)誤應(yīng)該交給硬件層面去處理。如果設(shè)備控制器發(fā)現(xiàn)了讀錯(cuò)誤的話,它會(huì)盡可能的去修復(fù)這個(gè)錯(cuò)誤。如果設(shè)備控制器處理不了這個(gè)問題,那么設(shè)備驅(qū)動(dòng)程序應(yīng)該進(jìn)行處理,設(shè)備驅(qū)動(dòng)程序會(huì)再次嘗試讀取操作,很多錯(cuò)誤都是偶然性的,如果設(shè)備驅(qū)動(dòng)程序無(wú)法處理這個(gè)錯(cuò)誤,才會(huì)把錯(cuò)誤向上拋到硬件層面(上層)進(jìn)行處理,很多時(shí)候,上層并不需要知道下層是如何解決錯(cuò)誤的。這就很像項(xiàng)目經(jīng)理不用把每個(gè)決定都告訴老板;程序員不用把每行代碼如何寫告訴項(xiàng)目經(jīng)理。這種處理方式不夠透明。

同步和異步傳輸

I/O 軟件實(shí)現(xiàn)的第三個(gè)目標(biāo)就是 同步(synchronous) 和 異步(asynchronous,即中斷驅(qū)動(dòng))傳輸。這里先說一下同步和異步是怎么回事吧。

同步傳輸中數(shù)據(jù)通常以塊或幀的形式發(fā)送。發(fā)送方和接收方在數(shù)據(jù)傳輸之前應(yīng)該具有同步時(shí)鐘。而在異步傳輸中,數(shù)據(jù)通常以字節(jié)或者字符的形式發(fā)送,異步傳輸則不需要同步時(shí)鐘,但是會(huì)在傳輸之前向數(shù)據(jù)添加奇偶校驗(yàn)位。下面是同步和異步的主要區(qū)別

 

回到正題。大部分物理IO(physical I/O) 是異步的。物理 I/O 中的 CPU 是很聰明的,CPU 傳輸完成后會(huì)轉(zhuǎn)而做其他事情,它和中斷心靈相通,等到中斷發(fā)生后,CPU 才會(huì)回到傳輸這件事情上來(lái)。

I/O 分為兩種:物理I/O 和 邏輯I/O(Logical I/O)。

物理 I/O 通常是從磁盤等存儲(chǔ)設(shè)備實(shí)際獲取數(shù)據(jù)。邏輯 I/O 是對(duì)存儲(chǔ)器(塊,緩沖區(qū))獲取數(shù)據(jù)。

緩沖

I/O 軟件的最后一個(gè)問題是緩沖(buffering)。通常情況下,從一個(gè)設(shè)備發(fā)出的數(shù)據(jù)不會(huì)直接到達(dá)最后的設(shè)備。其間會(huì)經(jīng)過一系列的校驗(yàn)、檢查、緩沖等操作才能到達(dá)。舉個(gè)例子來(lái)說,從網(wǎng)絡(luò)上發(fā)送一個(gè)數(shù)據(jù)包,會(huì)經(jīng)過一系列檢查之后首先到達(dá)緩沖區(qū),從而消除緩沖區(qū)填滿速率和緩沖區(qū)過載。

共享和獨(dú)占

I/O 軟件引起的最后一個(gè)問題就是共享設(shè)備和獨(dú)占設(shè)備的問題。有些 I/O 設(shè)備能夠被許多用戶共同使用。一些設(shè)備比如磁盤,讓多個(gè)用戶使用一般不會(huì)產(chǎn)生什么問題,但是某些設(shè)備必須具有獨(dú)占性,即只允許單個(gè)用戶使用完成后才能讓其他用戶使用。

下面,我們來(lái)探討一下如何使用程序來(lái)控制 I/O 設(shè)備。一共有三種控制 I/O 設(shè)備的方法

  • 使用程序控制 I/O
  • 使用中斷驅(qū)動(dòng) I/O
  • 使用 DMA 驅(qū)動(dòng) I/O

使用程序控制 I/O

使用程序控制 I/O 又被稱為 可編程I/O,它是指由 CPU 在驅(qū)動(dòng)程序軟件控制下啟動(dòng)的數(shù)據(jù)傳輸,來(lái)訪問設(shè)備上的寄存器或者其他存儲(chǔ)器。CPU 會(huì)發(fā)出命令,然后等待 I/O 操作的完成。由于 CPU 的速度比 I/O 模塊的速度快很多,因此可編程 I/O 的問題在于,CPU 必須等待很長(zhǎng)時(shí)間才能等到處理結(jié)果。CPU 在等待時(shí)會(huì)采用輪詢(polling)或者 忙等(busy waiting) 的方式,結(jié)果,整個(gè)系統(tǒng)的性能被嚴(yán)重拉低??删幊?I/O 十分簡(jiǎn)單,如果需要等待的時(shí)間非常短的話,可編程 I/O 倒是一個(gè)很好的方式。一個(gè)可編程的 I/O 會(huì)經(jīng)歷如下操作

  • CPU 請(qǐng)求 I/O 操作
  • I/O 模塊執(zhí)行響應(yīng)
  • I/O 模塊設(shè)置狀態(tài)位
  • CPU 會(huì)定期檢查狀態(tài)位
  • I/O 不會(huì)直接通知 CPU 操作完成
  • I/O 也不會(huì)中斷 CPU
  • CPU 可能會(huì)等待或在隨后的過程中返回

 

使用中斷驅(qū)動(dòng) I/O

鑒于上面可編程 I/O 的缺陷,我們提出一種改良方案,我們想要在 CPU 等待 I/O 設(shè)備的同時(shí),能夠做其他事情,等到 I/O 設(shè)備完成后,它就會(huì)產(chǎn)生一個(gè)中斷,這個(gè)中斷會(huì)停止當(dāng)前進(jìn)程并保存當(dāng)前的狀態(tài)。一個(gè)可能的示意圖如下

 

盡管中斷減輕了 CPU 和 I/O 設(shè)備的等待時(shí)間的負(fù)擔(dān),但是由于還需要在 CPU 和 I/O 模塊之前進(jìn)行大量的逐字傳輸,因此在大量數(shù)據(jù)傳輸中效率仍然很低。下面是中斷的基本操作

  • CPU 進(jìn)行讀取操作
  • I/O 設(shè)備從外圍設(shè)備獲取數(shù)據(jù),同時(shí) CPU 執(zhí)行其他操作
  • I/O 設(shè)備中斷通知 CPU
  • CPU 請(qǐng)求數(shù)據(jù)
  • I/O 模塊傳輸數(shù)據(jù)

所以我們現(xiàn)在著手需要解決的就是 CPU 和 I/O 模塊間數(shù)據(jù)傳輸?shù)男蕟栴}。

使用 DMA 的 I/O

DMA 的中文名稱是直接內(nèi)存訪問,它意味著 CPU 授予 I/O 模塊權(quán)限在不涉及 CPU 的情況下讀取或?qū)懭雰?nèi)存。也就是 DMA 可以不需要 CPU 的參與。這個(gè)過程由稱為 DMA 控制器(DMAC)的芯片管理。由于 DMA 設(shè)備可以直接在內(nèi)存之間傳輸數(shù)據(jù),而不是使用 CPU 作為中介,因此可以緩解總線上的擁塞。DMA 通過允許 CPU 執(zhí)行任務(wù),同時(shí) DMA 系統(tǒng)通過系統(tǒng)和內(nèi)存總線傳輸數(shù)據(jù)來(lái)提高系統(tǒng)并發(fā)性。

 

2.I/O 層次結(jié)構(gòu)

I/O 軟件通常組織成四個(gè)層次,它們的大致結(jié)構(gòu)如下圖所示

 

每一層和其上下層都有明確的功能和接口。下面我們采用和計(jì)算機(jī)網(wǎng)絡(luò)相反的套路,即自下而上的了解一下這些程序。

下面是另一幅圖,這幅圖顯示了輸入/輸出軟件系統(tǒng)所有層及其主要功能。

 

下面我們具體的來(lái)探討一下上面的層次結(jié)構(gòu)

中斷處理程序

在計(jì)算機(jī)系統(tǒng)中,中斷就像女人的脾氣一樣無(wú)時(shí)無(wú)刻都在產(chǎn)生,中斷的出現(xiàn)往往是讓人很不爽的。中斷處理程序又被稱為中斷服務(wù)程序 或者是 ISR(Interrupt Service Routines),它是最靠近硬件的一層。中斷處理程序由硬件中斷、軟件中斷或者是軟件異常啟動(dòng)產(chǎn)生的中斷,用于實(shí)現(xiàn)設(shè)備驅(qū)動(dòng)程序或受保護(hù)的操作模式(例如系統(tǒng)調(diào)用)之間的轉(zhuǎn)換。

中斷處理程序負(fù)責(zé)處理中斷發(fā)生時(shí)的所有操作,操作完成后阻塞,然后啟動(dòng)中斷驅(qū)動(dòng)程序來(lái)解決阻塞。通常會(huì)有三種通知方式,依賴于不同的具體實(shí)現(xiàn)

  • 信號(hào)量實(shí)現(xiàn)中:在信號(hào)量上使用 up 進(jìn)行通知;
  • 管程實(shí)現(xiàn):對(duì)管程中的條件變量執(zhí)行 signal 操作
  • 還有一些情況是發(fā)送一些消息

不管哪種方式都是為了讓阻塞的中斷處理程序恢復(fù)運(yùn)行。

中斷處理方案有很多種,下面是 《ARM System Developer’s Guide

Designing and Optimizing System Software》列出來(lái)的一些方案

  • 非嵌套的中斷處理程序按照順序處理各個(gè)中斷,非嵌套的中斷處理程序也是最簡(jiǎn)單的中斷處理
  • 嵌套的中斷處理程序會(huì)處理多個(gè)中斷而無(wú)需分配優(yōu)先級(jí)
  • 可重入的中斷處理程序可使用優(yōu)先級(jí)處理多個(gè)中斷
  • 簡(jiǎn)單優(yōu)先級(jí)中斷處理程序可處理簡(jiǎn)單的中斷
  • 標(biāo)準(zhǔn)優(yōu)先級(jí)中斷處理程序比低優(yōu)先級(jí)的中斷處理程序在更短的時(shí)間能夠處理優(yōu)先級(jí)更高的中斷
  • 高優(yōu)先級(jí) 中斷處理程序在短時(shí)間能夠處理優(yōu)先級(jí)更高的任務(wù),并直接進(jìn)入特定的服務(wù)例程。
  • 優(yōu)先級(jí)分組中斷處理程序能夠處理不同優(yōu)先級(jí)的中斷任務(wù)

下面是一些通用的中斷處理程序的步驟,不同的操作系統(tǒng)實(shí)現(xiàn)細(xì)節(jié)不一樣

  • 保存所有沒有被中斷硬件保存的寄存器
  • 為中斷服務(wù)程序設(shè)置上下文環(huán)境,可能包括設(shè)置 TLB、MMU 和頁(yè)表,如果不太了解這三個(gè)概念,請(qǐng)參考另外一篇文章
  • 為中斷服務(wù)程序設(shè)置棧
  • 對(duì)中斷控制器作出響應(yīng),如果不存在集中的中斷控制器,則繼續(xù)響應(yīng)中斷
  • 把寄存器從保存它的地方拷貝到進(jìn)程表中
  • 運(yùn)行中斷服務(wù)程序,它會(huì)從發(fā)出中斷的設(shè)備控制器的寄存器中提取信息
  • 操作系統(tǒng)會(huì)選擇一個(gè)合適的進(jìn)程來(lái)運(yùn)行。如果中斷造成了一些優(yōu)先級(jí)更高的進(jìn)程變?yōu)榫途w態(tài),則選擇運(yùn)行這些優(yōu)先級(jí)高的進(jìn)程
  • 為進(jìn)程設(shè)置 MMU 上下文,可能也會(huì)需要 TLB,根據(jù)實(shí)際情況決定
  • 加載進(jìn)程的寄存器,包括 PSW 寄存器
  • 開始運(yùn)行新的進(jìn)程

上面我們羅列了一些大致的中斷步驟,不同性質(zhì)的操作系統(tǒng)和中斷處理程序能夠處理的中斷步驟和細(xì)節(jié)也不盡相同,下面是一個(gè)嵌套中斷的具體運(yùn)行步驟

 

設(shè)備驅(qū)動(dòng)程序

在上面的文章中我們知道了設(shè)備控制器所做的工作。我們知道每個(gè)控制器其內(nèi)部都會(huì)有寄存器用來(lái)和設(shè)備進(jìn)行溝通,發(fā)送指令,讀取設(shè)備的狀態(tài)等。

因此,每個(gè)連接到計(jì)算機(jī)的 I/O 設(shè)備都需要有某些特定設(shè)備的代碼對(duì)其進(jìn)行控制,例如鼠標(biāo)控制器需要從鼠標(biāo)接受指令,告訴下一步應(yīng)該移動(dòng)到哪里,鍵盤控制器需要知道哪個(gè)按鍵被按下等。這些提供 I/O 設(shè)備到設(shè)備控制器轉(zhuǎn)換的過程的代碼稱為設(shè)備驅(qū)動(dòng)程序(Device driver)。

為了能夠訪問設(shè)備的硬件,實(shí)際上也就意味著,設(shè)備驅(qū)動(dòng)程序通常是操作系統(tǒng)內(nèi)核的一部分,至少現(xiàn)在的體系結(jié)構(gòu)是這樣的。但是也可以構(gòu)造用戶空間的設(shè)備驅(qū)動(dòng)程序,通過系統(tǒng)調(diào)用來(lái)完成讀寫操作。這樣就避免了一個(gè)問題,有問題的驅(qū)動(dòng)程序會(huì)干擾內(nèi)核,從而造成崩潰。所以,在用戶控件實(shí)現(xiàn)設(shè)備驅(qū)動(dòng)程序是構(gòu)造系統(tǒng)穩(wěn)定性一個(gè)非常有用的措施。MINIX 3 就是這么做的。下面是 MINI 3 的調(diào)用過程

 

然而,大多數(shù)桌面操作系統(tǒng)要求驅(qū)動(dòng)程序必須運(yùn)行在內(nèi)核中。

操作系統(tǒng)通常會(huì)將驅(qū)動(dòng)程序歸為 字符設(shè)備 和 塊設(shè)備,我們上面也介紹過了

 

在 UNIX 系統(tǒng)中,操作系統(tǒng)是一個(gè)二進(jìn)制程序,包含需要編譯到其內(nèi)部的所有驅(qū)動(dòng)程序,如果你要對(duì) UNIX 添加一個(gè)新設(shè)備,需要重新編譯內(nèi)核,將新的驅(qū)動(dòng)程序裝到二進(jìn)制程序中。

然而隨著大多數(shù)個(gè)人計(jì)算機(jī)的出現(xiàn),由于 I/O 設(shè)備的廣泛應(yīng)用,上面這種靜態(tài)編譯的方式不再有效,因此,從 MS-DOS 開始,操作系統(tǒng)轉(zhuǎn)向驅(qū)動(dòng)程序在執(zhí)行期間動(dòng)態(tài)的裝載到系統(tǒng)中。

設(shè)備驅(qū)動(dòng)程序具有很多功能,比如接受讀寫請(qǐng)求,對(duì)設(shè)備進(jìn)行初始化、管理電源和日志、對(duì)輸入?yún)?shù)進(jìn)行有效性檢查等。

設(shè)備驅(qū)動(dòng)程序接受到讀寫請(qǐng)求后,會(huì)檢查當(dāng)前設(shè)備是否在使用,如果設(shè)備在使用,請(qǐng)求被排入隊(duì)列中,等待后續(xù)的處理。如果此時(shí)設(shè)備是空閑的,驅(qū)動(dòng)程序會(huì)檢查硬件以了解請(qǐng)求是否能夠被處理。在傳輸開始前,會(huì)啟動(dòng)設(shè)備或者馬達(dá)。等待設(shè)備就緒完成,再進(jìn)行實(shí)際的控制??刂圃O(shè)備就是對(duì)設(shè)備發(fā)出指令。

發(fā)出命令后,設(shè)備控制器便開始將它們寫入控制器的設(shè)備寄存器。在將每個(gè)命令寫入控制器后,會(huì)檢查控制器是否接受了這條命令并準(zhǔn)備接受下一個(gè)命令。一般控制設(shè)備會(huì)發(fā)出一系列的指令,這稱為指令序列,設(shè)備控制器會(huì)依次檢查每個(gè)命令是否被接受,下一條指令是否能夠被接收,直到所有的序列發(fā)出為止。

 

 

發(fā)出指令后,一般會(huì)有兩種可能出現(xiàn)的情況。在大多數(shù)情況下,設(shè)備驅(qū)動(dòng)程序會(huì)進(jìn)行等待直到控制器完成它的事情。這里需要了解一下設(shè)備控制器的概念

設(shè)備控制器的主要主責(zé)是控制一個(gè)或多個(gè) I/O 設(shè)備,以實(shí)現(xiàn) I/O 設(shè)備和計(jì)算機(jī)之間的數(shù)據(jù)交換。

設(shè)備控制器接收從 CPU 發(fā)送過來(lái)的指令,繼而達(dá)到控制硬件的目的

設(shè)備控制器是一個(gè)可編址的設(shè)備,當(dāng)它僅控制一個(gè)設(shè)備時(shí),它只有一個(gè)唯一的設(shè)備地址;如果設(shè)備控制器控制多個(gè)可連接設(shè)備時(shí),則應(yīng)含有多個(gè)設(shè)備地址,并使每一個(gè)設(shè)備地址對(duì)應(yīng)一個(gè)設(shè)備。

設(shè)備控制器主要分為兩種:字符設(shè)備和塊設(shè)備

設(shè)備控制器的主要功能有下面這些

  • 接收和識(shí)別命令:設(shè)備控制器可以接受來(lái)自 CPU 的指令,并進(jìn)行識(shí)別。設(shè)備控制器內(nèi)部也會(huì)有寄存器,用來(lái)存放指令和參數(shù)
  • 進(jìn)行數(shù)據(jù)交換:CPU、控制器和設(shè)備之間會(huì)進(jìn)行數(shù)據(jù)的交換,CPU 通過總線把指令發(fā)送給控制器,或從控制器中并行地讀出數(shù)據(jù);控制器將數(shù)據(jù)寫入指定設(shè)備。
  • 地址識(shí)別:每個(gè)硬件設(shè)備都有自己的地址,設(shè)備控制器能夠識(shí)別這些不同的地址,來(lái)達(dá)到控制硬件的目的,此外,為使 CPU 能向寄存器中寫入或者讀取數(shù)據(jù),這些寄存器都應(yīng)具有唯一的地址。
  • 差錯(cuò)檢測(cè):設(shè)備控制器還具有對(duì)設(shè)備傳遞過來(lái)的數(shù)據(jù)進(jìn)行檢測(cè)的功能。

在這種情況下,設(shè)備控制器會(huì)阻塞,直到中斷來(lái)解除阻塞狀態(tài)。還有一種情況是操作是可以無(wú)延遲的完成,所以驅(qū)動(dòng)程序不需要阻塞。在第一種情況下,操作系統(tǒng)可能被中斷喚醒;第二種情況下操作系統(tǒng)不會(huì)被休眠。

設(shè)備驅(qū)動(dòng)程序必須是可重入的,因?yàn)樵O(shè)備驅(qū)動(dòng)程序會(huì)阻塞和喚醒然后再次阻塞。驅(qū)動(dòng)程序不允許進(jìn)行系統(tǒng)調(diào)用,但是它們通常需要與內(nèi)核的其余部分進(jìn)行交互。

與設(shè)備無(wú)關(guān)的 I/O 軟件

I/O 軟件有兩種,一種是我們上面介紹過的基于特定設(shè)備的,還有一種是設(shè)備無(wú)關(guān)性的,設(shè)備無(wú)關(guān)性也就是不需要特定的設(shè)備。設(shè)備驅(qū)動(dòng)程序與設(shè)備無(wú)關(guān)的軟件之間的界限取決于具體的系統(tǒng)。下面顯示的功能由設(shè)備無(wú)關(guān)的軟件實(shí)現(xiàn)

 

與設(shè)備無(wú)關(guān)的軟件的基本功能是對(duì)所有設(shè)備執(zhí)行公共的 I/O 功能,并且向用戶層軟件提供一個(gè)統(tǒng)一的接口。

緩沖

無(wú)論是對(duì)于塊設(shè)備還是字符設(shè)備來(lái)說,緩沖都是一個(gè)非常重要的考量標(biāo)準(zhǔn)。下面是從 ADSL(調(diào)制解調(diào)器) 讀取數(shù)據(jù)的過程,調(diào)制解調(diào)器是我們用來(lái)聯(lián)網(wǎng)的設(shè)備。

用戶程序調(diào)用 read 系統(tǒng)調(diào)用阻塞用戶進(jìn)程,等待字符的到來(lái),這是對(duì)到來(lái)的字符進(jìn)行處理的一種方式。每一個(gè)到來(lái)的字符都會(huì)造成中斷。中斷服務(wù)程序會(huì)給用戶進(jìn)程提供字符,并解除阻塞。將字符提供給用戶程序后,進(jìn)程會(huì)去讀取其他字符并繼續(xù)阻塞,這種模型如下

 

 

這一種方案是沒有緩沖區(qū)的存在,因?yàn)橛脩暨M(jìn)程如果讀不到數(shù)據(jù)會(huì)阻塞,直到讀到數(shù)據(jù)為止,這種情況效率比較低,而且阻塞式的方式,會(huì)直接阻止用戶進(jìn)程做其他事情,這對(duì)用戶來(lái)說是不能接受的。還有一種情況就是每次用戶進(jìn)程都會(huì)重啟,對(duì)于每個(gè)字符的到來(lái)都會(huì)重啟用戶進(jìn)程,這種效率會(huì)嚴(yán)重降低,所以無(wú)緩沖區(qū)的軟件不是一個(gè)很好的設(shè)計(jì)。

作為一個(gè)改良點(diǎn),我們可以嘗試在用戶空間中使用一個(gè)能讀取 n 個(gè)字節(jié)緩沖區(qū)來(lái)讀取 n 個(gè)字符。這樣的話,中斷服務(wù)程序會(huì)把字符放到緩沖區(qū)中直到緩沖區(qū)變滿為止,然后再去喚醒用戶進(jìn)程。這種方案要比上面的方案改良很多。

 

但是這種方案也存在問題,當(dāng)字符到來(lái)時(shí),如果緩沖區(qū)被調(diào)出內(nèi)存會(huì)出現(xiàn)什么問題?解決方案是把緩沖區(qū)鎖定在內(nèi)存中,但是這種方案也會(huì)出現(xiàn)問題,如果少量的緩沖區(qū)被鎖定還好,如果大量的緩沖區(qū)被鎖定在內(nèi)存中,那么可以換進(jìn)換出的頁(yè)面就會(huì)收縮,造成系統(tǒng)性能的下降。

一種解決方案是在內(nèi)核中內(nèi)部創(chuàng)建一塊緩沖區(qū),讓中斷服務(wù)程序?qū)⒆址旁趦?nèi)核內(nèi)部的緩沖區(qū)中。

 

當(dāng)內(nèi)核中的緩沖區(qū)要滿的時(shí)候,會(huì)將用戶空間中的頁(yè)面調(diào)入內(nèi)存,然后將內(nèi)核空間的緩沖區(qū)復(fù)制到用戶空間的緩沖區(qū)中,這種方案也面臨一個(gè)問題就是假如用戶空間的頁(yè)面被換入內(nèi)存,此時(shí)內(nèi)核空間的緩沖區(qū)已滿,這時(shí)候仍有新的字符到來(lái),這個(gè)時(shí)候會(huì)怎么辦?因?yàn)榫彌_區(qū)滿了,沒有空間來(lái)存儲(chǔ)新的字符了。

一種非常簡(jiǎn)單的方式就是再設(shè)置一個(gè)緩沖區(qū)就行了,在第一個(gè)緩沖區(qū)填滿后,在緩沖區(qū)清空前,使用第二個(gè)緩沖區(qū),這種解決方式如下

 

當(dāng)?shù)诙€(gè)緩沖區(qū)也滿了的時(shí)候,它也會(huì)把數(shù)據(jù)復(fù)制到用戶空間中,然后第一個(gè)緩沖區(qū)用于接受新的字符。這種具有兩個(gè)緩沖區(qū)的設(shè)計(jì)被稱為 雙緩沖(double buffering)。

還有一種緩沖形式是 循環(huán)緩沖(circular buffer)。它由一個(gè)內(nèi)存區(qū)域和兩個(gè)指針組成。一個(gè)指針指向下一個(gè)空閑字,新的數(shù)據(jù)可以放在此處。另外一個(gè)指針指向緩沖區(qū)中尚未刪除數(shù)據(jù)的第一個(gè)字。在許多情況下,硬件會(huì)在添加新的數(shù)據(jù)時(shí),移動(dòng)第一個(gè)指針;而操作系統(tǒng)會(huì)在刪除和處理無(wú)用數(shù)據(jù)時(shí)會(huì)移動(dòng)第二個(gè)指針。兩個(gè)指針到達(dá)頂部時(shí)就回到底部重新開始。

緩沖區(qū)對(duì)輸出來(lái)說也很重要。對(duì)輸出的描述和輸入相似

緩沖技術(shù)應(yīng)用廣泛,但它也有缺點(diǎn)。如果數(shù)據(jù)被緩沖次數(shù)太多,會(huì)影響性能??紤]例如如下這種情況,

 

 

 

 

數(shù)據(jù)經(jīng)過用戶進(jìn)程 -> 內(nèi)核空間 -> 網(wǎng)絡(luò)控制器,這里的網(wǎng)絡(luò)控制器應(yīng)該就相當(dāng)于是 socket 緩沖區(qū),然后發(fā)送到網(wǎng)絡(luò)上,再到接收方的網(wǎng)絡(luò)控制器 -> 接收方的內(nèi)核緩沖 -> 接收方的用戶緩沖,一條數(shù)據(jù)包被緩存了太多次,很容易降低性能。

錯(cuò)誤處理

在 I/O 中,出錯(cuò)是一種再正常不過的情況了。當(dāng)出錯(cuò)發(fā)生時(shí),操作系統(tǒng)必須盡可能處理這些錯(cuò)誤。有一些錯(cuò)誤是只有特定的設(shè)備才能處理,有一些是由框架進(jìn)行處理,這些錯(cuò)誤和特定的設(shè)備無(wú)關(guān)。

I/O 錯(cuò)誤的一類是程序員編程錯(cuò)誤,比如還沒有打開文件前就讀流,或者不關(guān)閉流導(dǎo)致內(nèi)存溢出等等。這類問題由程序員處理;另外一類是實(shí)際的 I/O 錯(cuò)誤,例如向一個(gè)磁盤壞塊寫入數(shù)據(jù),無(wú)論怎么寫都寫入不了。這類問題由驅(qū)動(dòng)程序處理,驅(qū)動(dòng)程序處理不了交給硬件處理,這個(gè)我們上面也說過。

設(shè)備驅(qū)動(dòng)程序統(tǒng)一接口

我們?cè)诓僮飨到y(tǒng)概述中說到,操作系統(tǒng)一個(gè)非常重要的功能就是屏蔽了硬件和軟件的差異性,為硬件和軟件提供了統(tǒng)一的標(biāo)準(zhǔn),這個(gè)標(biāo)準(zhǔn)還體現(xiàn)在為設(shè)備驅(qū)動(dòng)程序提供統(tǒng)一的接口,因?yàn)椴煌挠布蛷S商編寫的設(shè)備驅(qū)動(dòng)程序不同,所以如果為每個(gè)驅(qū)動(dòng)程序都單獨(dú)提供接口的話,這樣沒法搞,所以必須統(tǒng)一。

分配和釋放

一些設(shè)備例如打印機(jī),它只能由一個(gè)進(jìn)程來(lái)使用,這就需要操作系統(tǒng)根據(jù)實(shí)際情況判斷是否能夠?qū)υO(shè)備的請(qǐng)求進(jìn)行檢查,判斷是否能夠接受其他請(qǐng)求,一種比較簡(jiǎn)單直接的方式是在特殊文件上執(zhí)行 open操作。如果設(shè)備不可用,那么直接 open 會(huì)導(dǎo)致失敗。還有一種方式是不直接導(dǎo)致失敗,而是讓其阻塞,等到另外一個(gè)進(jìn)程釋放資源后,在進(jìn)行 open 打開操作。這種方式就把選擇權(quán)交給了用戶,由用戶判斷是否應(yīng)該等待。

注意:阻塞的實(shí)現(xiàn)有多種方式,有阻塞隊(duì)列等

設(shè)備無(wú)關(guān)的塊

不同的磁盤會(huì)具有不同的扇區(qū)大小,但是軟件不會(huì)關(guān)心扇區(qū)大小,只管存儲(chǔ)就是了。一些字符設(shè)備可以一次一個(gè)字節(jié)的交付數(shù)據(jù),而其他的設(shè)備則以較大的單位交付數(shù)據(jù),這些差異也可以隱藏起來(lái)。

用戶空間的 I/O 軟件

雖然大部分 I/O 軟件都在內(nèi)核結(jié)構(gòu)中,但是還有一些在用戶空間實(shí)現(xiàn)的 I/O 軟件,凡事沒有絕對(duì)。一些 I/O 軟件和庫(kù)過程在用戶空間存在,然后以提供系統(tǒng)調(diào)用的方式實(shí)現(xiàn)。

 

責(zé)任編輯:武曉燕 來(lái)源: 程序員cxuan
相關(guān)推薦

2019-02-28 10:37:19

開源數(shù)據(jù)庫(kù)Oracle

2018-10-07 06:30:40

代碼設(shè)計(jì)模式面向?qū)ο笤瓌t

2020-12-14 07:31:57

JDKJVM監(jiān)控

2021-06-09 10:10:20

代碼內(nèi)存編程語(yǔ)言

2021-03-24 08:44:11

代碼內(nèi)存消耗語(yǔ)言

2021-09-08 22:38:56

區(qū)塊鏈公有鏈網(wǎng)絡(luò)

2020-04-10 08:44:15

5G基站天線

2018-11-05 11:20:54

緩沖IO

2022-12-26 07:43:44

SpringBootWeb 類框架的

2022-08-11 17:14:37

Java

2022-12-09 09:46:55

插件Lombok

2019-12-10 10:13:58

HTTPNginxRedirect

2024-02-20 08:09:51

Java 8DateUtilsDate工具類

2023-11-13 08:49:54

2014-08-26 11:03:54

2015-08-25 08:54:59

物聯(lián)網(wǎng)

2021-02-16 16:43:21

工具性能調(diào)優(yōu)

2023-09-08 07:34:11

編輯器React

2024-05-13 16:22:25

固態(tài)硬盤接口硬盤

2021-08-09 11:32:30

左葉子節(jié)點(diǎn)二叉樹
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)