操作系統基礎概念

基本概念

操作系統(Operating System,簡稱OS)是管理系統資源、控制程序執行、改善人機界面、提供各種服務、合理組織計算機工作流程和爲用戶有效使用計算機提供良好運行環境的一種系統軟件。

操作系統的主要功能是資源管理運行程序,OS直接安裝在硬件上,屏蔽硬件細節,向上提供統一抽象接口。

  • 運行程序:編譯鏈接形成可執行文件→外存→內存分配空間→加上PCB控制塊形成進程→執行程序→回收內存等軟硬件資源

  • 資源包括硬件與軟件資源,硬件資源包括CPU、內存、外存、輸入輸出設備等。資源管理包括處理器管理(進程/線程)、存儲管理(內存)、設備管理(I/O)、文件管理、網絡與通信管理等

操作系統的資源管理技術主要包括:

  • 資源複用:指多個進程共享物理資源,包括分割資源爲較多更小單位的空分複用和分時輪流使用資源的時分複用。進程是有資格獲得系統資源的獨立主體。
  • 資源虛化:指利用一類事物模擬另外一類事物,造成另外一類事物數量更多或容量更大的假象。如虛擬內存映射。
  • 資源抽象:指利用軟件封裝複雜的硬件或軟件設施,簡化資源應用接口的一種資源管理技術。

操作系統的主要目標爲:

  • 方便用戶使用:儘量屏蔽硬件細節,向上提供統一抽象接口
  • 擴充機器功能:在固有硬件的基礎上安裝使用各種各樣的軟件,提供多種服務
  • 管理系統資源:幫助管理各種軟硬件資源
  • 提高系統效率:OS可自我管理
  • 構築開放環境:平臺移植性與各操作系統間的互聯互操作性

操作系統特性:

  • 併發性(Concurrence):指兩個或兩個以上的事件或活動在同一時間間隔內發生。(對應的,並行性(parallelism)是指兩個或兩個以上的事件或活動在同一時刻發生。)。操作系統的併發性是指計算機系統中同時存在若干個運行着的程序,這些程序交替、穿插地執行。
  • 共享性:指操作系統中的資源可被多個併發執行的進程共同使用,而不是被其中某一個程序所獨佔。
  • 異步性:是併發性的表現特徵,在多道程序環境中,程序的執行不是一貫到底,而是“走走停停”,何時“走”,何時“停”是不可預知的。併發執行與順序執行效果一致
  • 虛擬性:是操作系統資源管理技術的特性,虛擬資源管理技術即資源虛化,將物理上的一個實體變成邏輯上的多個對應物,或把物理上的多個實體變成邏輯上的一個對應物。

單道程序設計與多道程序設計

涉及到操作系統的發展歷史,在打卡片的年代裏,程序運行時的很多步驟都手動處理,單道程序即一次只執行一個程序,多道程序設計則是指允許多個程序同時進入一個計算機系統的主存儲器並啓動進行交替計算的方法(並行性,如在CPU運轉的時候另一個程序的輸入也可同時進行)CPU利用率=(CPU運轉時間/同一時間所處理的所有程序的總運行時間)

內核:OS在硬件上的首層抽象,屏蔽硬件細節,向上提供統一抽象接口

系統調用:內核中函數,獲取操作系統服務的唯一途徑

系統調用過程:請求系統調用→由用戶態轉換爲核心態→發生中斷,現場保護→執行完畢,內核(系統)調用返回

系統調用與過程(函數)調用的區別

(1)調用形式不同
過程(函數)使用一般調用指令,其轉向地址包含在跳轉語句中;系統調用不包含處理程序入口,僅僅提供功能號,按功能號調用。
(2)被調用代碼的位置不同
在過程(函數)調用中,調用程序和被調用代碼在同一程序內,經過連接編譯後作爲目標代碼的一部分。當過程(函數)升級或修改時,必須重新編譯連接。
系統調用的處理代碼在調用程序之外(在操作系統中),系統調用處理代碼升級或修改時,與調用程序無關。
(3)提供方式不同
過程(函數)由編譯系統提供或用戶編寫,不同編譯系統提供的過程(函數)可以不同;
系統調用由操作系統提供,一旦操作系統設計好,系統調用的功能、種類與數量就固定不變了。
(4)調用的實現不同
程序使用一般機器指令(跳轉指令)來調用過程(函數),是在用戶態運行的;
程序執行系統調用,是通過中斷機構來實現的,需要從用戶態轉變到核心態,在管理態執行。

操作接口:是操作系統爲用戶提供的操作控制計算機工作和提供服務手段的集合。包括圖形用戶界面,命令行工具等

OS結構

  • 單體式結構:整個OS爲一個大型可執行二進制文件,在內核中以單一程序方式運行

  • 層次式結構:將OS劃分爲內核與多個模塊,垂直排列,爲單向調用關係,低層爲高層提供服務

  • 客戶機/服務器與微內核結構:劃分功能模塊與微內核,功能模塊爲服務器進程,用戶進程爲客戶機進程,使用消息傳遞進行通信,用戶進程向服務器進程請求資源,內核管理服務器進程

OS運行模型

  • 非進程模式:將OS組織成一個例行程序,用戶程序/數據/堆棧+內核程序/數據/堆棧構成進程映像,操作系統本身不是一個進程,在其上的軟件運行時訪問內核,加上內核程序構成進程映像進行執行
  • 進程模式:將OS組織成一組系統進程,OS功能由這些系統進程集合提供

處理器管理

處理器

處理器屬於分時複用型的共享資源,其中的寄存器被操作系統和各個進程所共享,任意瞬時的寄存器內容構成處理器工作現場。當進程或任務發生切換時,寄存器內容必須被保存,以便進程或任務恢復執行時,還原處理器工作現場。

指令分特權指令與非特權指令:特權指令僅提供給操作系統核心程序使用

處理器狀態轉換

  1. 用戶態轉向管態:執行系統調用,請求操作系統服務;中斷事件產生,運行程序被中斷,操作系統接管處理器,中斷處理程序開始工作。
  2. 管態轉向用戶態:執行加載程序狀態字LPSW(Load PSW)指令時轉換。

PSW即程序狀態字,處理器的工作狀態記錄在程序狀態字(PSW)寄存器中;每個正在執行的程序都有一個與其執行相關的PSW(進程與一個PSW對應);每個處理器都設置一個程序狀態字寄存器。

PSW存儲的主要信息包括:

  • 程序基本狀態:程序計數器、處理器狀態位、條件碼等

  • 中斷碼:記錄發生的中斷事件

  • 中斷屏蔽位:決定是否響應中斷事件

中斷

中斷:指程序執行過程中發生某個事件時,終止CPU當前程序,轉而執行事件的過程

中斷是改變指令執行流程、實現操作系統併發多任務功能的重要硬件機構,也是操作系統實現計算機控制的重要途徑。檢測中斷的方法爲:在每兩條指令或某些特殊指令執行期間,每當一條指令執行結束時都檢測是否發生中斷以此來檢測並響應中斷。

中斷源是引起中斷的事件,中斷裝置是發現中斷源併產生中斷的硬件,當中斷事件發生後,它能改變處理器內操作執行的順序。

分類

  • 強迫性中斷:外部隨機事件引起,如電源故障,設備出錯等
  • 自願性中斷:程序自己引發的期待事件
  • 外中斷:處理器與主存之外的中斷,如時鐘中斷、I/O中斷等
  • 內中斷:處理器與主存內部的中斷,如地址越界,算術操作溢出等,內中斷不能屏蔽
  • 硬中斷:由硬件設施產生的中斷信號;硬中斷髮生時會立刻響應
  • 軟中斷:利用軟件模擬產生的中斷信號,用於實現內核與進程或進程與進程之間的通信;接收軟中斷的進程運行時才能響應

中斷與異常的區別

(1)中斷不是現行程序引發的,而是由與現行指令無關的中斷信號觸發的;異常是現行程序引發的
(2)中斷處理程序提供的服務一般不是現行程序需要的,通常兩條機器指令之間纔可響應中斷;異常是由程序本身產生的,異常處理一般是現行程序所需要的

中斷處理

使用硬件+軟件實現中斷處理,中斷寄存器存儲中斷字,中斷字每一位代表一箇中斷事件,每條指令執行完畢後檢查中斷字。中斷指令刺激中斷源產生中斷信號,中斷信號置中斷字對應位爲1,檢查中斷字發現中斷,CPU響應中斷請求,中斷位置0

發現中斷源,響應中斷請求→保護現場→啓動中斷處理程序→中斷返回

中斷處理程序主要用於處理事件與恢復現場,當響應中斷時調用中斷處理程序,然後保護現場,不同的中斷源對應不同的中斷處理程序,維護一箇中斷處理程序入口的向量表

問題1:在系統中只有一個進程運行時,該進程會不間斷地運行嗎?

不一定,只要發生了系統調用仍然會產生中斷,同時程序運行過程中會產生各種各應的中斷信號,如I/O中斷,時鐘中斷或各種內中斷,一般來說一個進程運行時不會不間斷的運行,總會產生某些中斷。

問題2:在系統中沒有任何進程運行時,操作系統在幹什麼?系統會靜止嗎?

不會,此時會有時鐘中斷處理程序在運行,等待服務程序的到來;中斷猶如計算機系統的心臟,無論何時不能停止跳動,否則,計算機系統將失去驅動力;中斷也像剎車,可以使用戶程序及系統程序適時停止運行,以便重新分配系統資源,尤其是處理器資源,避免某些程序過長時間地壟斷系統資源,破壞系統資源使用的公平性。

進程

進程是一個可併發執行的具有獨立功能的程序關於某個數據集合的一次執行過程,也是操作系統進行資源分配和保護的基本單位。

進程與程序的區別

(1)程序是靜態的,進程是動態的,進程是按照程序運行的過程。
(2)同一個程序在一段時間內可以同時存在多個執行活動(即進程)分別對不同的數據進行處理

進程的屬性

  • 結構性:進程包含了數據集合與運行於其上的程序,至少包含三個部分:程序塊、數據塊、進程控制快。進程=程序代碼+相關數據+PCB
  • 共享性:同一程序運行於不同數據集合上構成不同的進程
  • 動態性:進程的內容(主要是數據)是動態的,隨着指令的執行而變化;程序的內容是固定的。
  • 獨立性:進程是系統中資源分配和保護的基本單位,也是系統調度的獨立單位。
  • 制約性:併發進程之間存在同步、互斥關係;同步:存在協作關係的一個進程在某些執行點需要等待另一個進程發來的同步信號;互斥:共享某些資源的進程需要依次排隊使用這些資源。
  • 併發性:在單處理器系統環境下,各個進程輪流佔用處理器,即交替、穿插使用處理器。

進程狀態

劃分進程狀態對於簡潔、條理地分類管理進程、合理調度系統資源非常必要。

  1. 三態模型

進程至少包含程序代碼與數據集兩個部分,即包括一系列順序指令與該指令集合要操作的數據

要讓OS管理進程,則必須還加上進程控制塊(PCB),進程狀態

  • 運行態:佔用CPU,執行指令
  • 就緒態:具備運行條件,等待OS調度分配CPU以進入運行態
  • 等待態:進程等待事件發生,目前不能繼續執行,缺乏條件
  1. 五態模型
  • 新建態:進程剛被創建,尚未提交參加處理器競爭
  • 運行態:佔用CPU,執行指令
  • 就緒態:具備運行條件,等待OS調度分配CPU以進入運行態
  • 等待態:進程等待事件發生,目前不能繼續執行,缺乏條件
  • 終止態:進程已經終止,但是進程尚未退出主存
  1. 七態模型

在三態模型中,進程的運行、就緒、阻塞都由OS在內存中進行調度管理,隨着進程數的不斷增加,系統資源會被瓜分乾淨,爲了平滑系統負荷,必須把某些進程掛起換到磁盤鏡像中,因此引入掛起態:

  • 掛起就緒態:進程就緒但位於外存
  • 掛起等待態:進程阻塞並位於外存

OS控制結構:操作系統的控制結構是控制進程、管理系統資源的數據結構,同樣類型的數據結構組成表,稱爲控制表。

  • 進程控制表:登記進程管理信息,控制管理所有進程映像
  • 存儲控制表:管理主存與外存
  • I/O控制表:管理I/O設備與通道
  • 文件控制表:登記打開文件的狀態、屬性信息

進程實體/進程映像

進程實體包括程序塊、數據塊、進程控制快(PCB)、核心棧

進程控制塊PCB:進程創建時建立進程控制塊,進程撤銷時回收進程控制塊,進程控制塊與進程一一對應。主要包括標誌信息(唯一標識一個進程)、現場信息(讓出CPU時當下的CPU現場,便於後來恢復)、控制信息(用於管理和調度進程,如調度信息,資源清單等)等。

核心棧主要記錄進程運行在覈心態下時跟蹤過程調用和過程間參數傳遞信息

進程實體的內容隨着進程的執行不斷髮生變化,某時刻進程實體的內容及其狀態集合稱爲進程映像。

進程上下文

進程物理實體和支持進程運行的環境合稱爲進程上下文。進程物理實體主要包括PCB、程序塊、數據塊等,進程運行環境主要包括核心棧、用戶棧、寄存器等

進程隊列

處於同一狀態的所有PCB鏈接在一起的數據結構稱爲進程隊列。隊列可以按照進程狀態進行細分,如就緒隊列、等待隊列等,通過管理該隊列控制進程調度

進程切換

進程切換即中斷一個進程的執行轉而執行另一個進程。保存被中斷進程上下文到其進程控制塊中,然後裝入新進程上下文,使其從上次斷點恢復執行,或者調度一個新的進程。

進程調度的時機

(1)當進程進入等待態時:一個進程陷入阻塞,調一個就緒態的進程來執行
(2)當進程完成其系統調用返回用戶態,但不是最有資格獲得CPU時:把處理器分配給最有資格獲得它的進程,進程切換由此發生。
(3)當內核完成中斷處理,進程返回用戶態但不是最有資格獲得CPU時:發生強迫性中斷時的處理情況,同(2)
(4)當進程執行結束時:回收資源,調度處理其他進程

進程的調度依賴於中斷,中斷是激活操作系統的唯一方法,只有中斷髮生時操作系統才能接管處理器,纔有可能發生進程上下文的切換

進程切換的步驟(假設P1被中斷,調度P2開始執行):

中斷、保存P1現場信息→修改P1的PCB,將運行態改爲等待態或就緒態→將P1加入相關進程隊列(等待隊列或者就緒隊列)→在就緒隊列中選擇一個進程來執行,如P2→修改P2的PCB,將狀態改爲運行態→運行P2,直接執行或恢復上次斷點狀態繼續執行

進程切換包含兩次模式切換:一個進程的用戶態→管態;管態→另一個進程的用戶態

進程的控制與管理

OS對進程的控制與管理通過原語來實現

**原語是在管態下執行、完成系統特定功能的不可中斷的過程,具有原子操作性。**原語可以採用屏蔽中斷的系統調用來實現

(1)進程的創建:

①在主進程表中增加一項,並從PCB池中取一個空白PCB,爲新進程分配唯一的進程標識符

②爲新進程的進程映像分配地址空間,裝入程序和數據。

③爲新進程分配內存空間外的其它資源

④初始化進程控制塊,如進程標識符、處理器初始狀態、進程優先級等

⑤把進程狀態置爲就緒態並加入就緒進程隊列

⑥通知操作系統的某些模塊,如記賬程序、性能監控程序

(2)進程的阻塞:

進程阻塞是指一個進程讓出處理器,去等待一個事件。

①停止進程執行,保存現場信息到PCB

②修改PCB的有關內容,如進程狀態由運行改爲等待,並把修改狀態後的PCB加入相應等待隊列

③轉入進程調度程序調度其他進程運行

(3)進程的喚醒:

①從相應等待隊列中移出進程

②修改進程PCB有關信息,如進程狀態改爲就緒並把修改PCB後的進程加入就緒隊列

③若被喚醒進程優先級高於當前運行進程,則重新設置調度標誌

(4)進程的撤銷:

①根據撤銷進程標識號,從相應隊列找到它的PCB

②將該進程擁有的資源歸還給父進程或操作系統

③若該進程擁有子進程,則先撤銷它的所有子孫進程,以防它們脫離控制

④撤銷進程出隊,將它的PCB歸還到PCB池

(5)進程的掛起和激活:

掛起時:檢查要被掛起進程的狀態,若處於活動就緒態就修改爲掛起就緒態,若處於阻塞態,則修改爲掛起阻塞態。被掛起進程PCB的非常駐部分要交換到磁盤對換區。

激活時:把進程PCB非常駐部分調進內存,修改它的狀態,掛起等待態改爲等待態,掛起就緒態改爲就緒態,加入相應隊列中。

掛起原語既可由進程自己也可由其他進程調用,但激活原語只能由其它進程調用。

線程

線程:運行在同一個進程中的各個併發任務稱爲該進程的線程。線程是處理器調度的基本單位

線程實體

線程控制塊TCB:包含唯一標識符、狀態信息、線程上下文等

私有存儲區:包含局部變量,用戶棧等

核心棧:線程在覈心態工作下存放的函數調用傳遞的參數、返回地址等信息

線程狀態

只有三個關鍵狀態:運行、就緒、等待(阻塞)

多線程優點

切換速度快、切換開銷小
易於實現任務間的通信協作
提高併發度

多線程實現

  • 用戶級線程:由程序自己實現,操作系統不參與調度
  • 內核級線程:內核級線程是在操作系統內核層對進程實現的多線程功能,操作系統以線程作爲處理器調度和分派的基本單位
  • 混合式線程:某些操作系統提供了同時支持用戶級線程與內核級線程的混合式線程設施,線程的創建、調度和同步在用戶空間進行。一個應用程序中的多個用戶級線程被映射到一些(小於或等於用戶級線程的數目)內核級線程上。

處理器調度

處理器調度考慮兩個問題:如何從多個作業中選擇一些作業加載到內存中併爲其創建進程?如何從多個進程中選擇一個進程交由CPU處理

高級調度:從磁盤後備作業隊列中挑選若干作業進入內存,爲其分配資源,創建進程,決定一個進程能否被創建及創建後能否被置位就緒態

中級調度:決定哪些進程進入掛起狀態,哪些進程從掛起狀態中被喚醒,即決定哪些進程參與競爭處理器資源,哪些進程換出到磁盤,哪些進程從磁盤中換入內存

低級調度:決定哪一個就緒進程佔用CPU,中斷是執行低級調度的時機

調度時選擇調度算法的因素

  • CPU利用率 = CPU有效工作時間/CPU總的運行時間
  • 吞吐率:單位時間內CPU處理的作業數
  • 公平性:至少確保不會出現飢餓現象(飢餓即調度時有的線程長時間佔用不到CPU,對於用戶來時就好像進程停止工作了一樣)
  • 響應時間:從提交一個請求到接收到響應之間的時間間隔,響應時間 = 命令傳輸到CPU的時間+CPU處理命令的時間+處理結果返回終端的時間
  • 週轉時間:作業提交給系統開始,到作業完成爲止的時間間隔,即週轉時間=完成時刻-提交時刻
  • 平均週轉時間:n個作業的總週轉時間/n
  • 帶權週轉時間:作業週轉時間(總時間)/作業運行時間
  • 平均帶權週轉時間:n個作業的總帶權週轉時間/n

作業、進程和線程

作業對應一個完整的業務處理過程,該過程包含若干個相對獨立又相互關聯的順序加工步驟,每個步驟對應着一個進程或線程

處理器調度算法

主要講低級調度算法,可以分爲兩種類型:

  • 剝奪方式:由OS剝奪正在運行的程序,將CPU交給其它進程/線程使用。常見的有兩種:高優先級剝奪:誰優先級高先運行誰;時間片剝奪:按時分方式時間片用完了就調度一次
  • 非剝奪方式:一旦某個進程或線程開始執行便不再出讓處理器,除非該進程或線程運行結束或發生了某個事件不能繼續執行。

兩者一般混合使用,內核關鍵程序使用非剝奪方式、用戶進程使用剝奪方式

調度算法

(1)先來先服務算法FCFS:誰先來就先服務誰,非剝奪

(2)最短作業優先算法SJF:對每一個到來的作業進行時間估計,那個時間最少就運行誰,非剝奪

(3)最短剩餘時間優先算法SRTF:對每一個到來的作業進行時間估計,對當前時刻的所有進程進行時間評估,時間少的可搶佔CPU優先處理,剝奪式

(4)響應比最高者優先算法HRRF:計算響應比,響應比 = 作業的響應時間/作業處理時間,選擇響應比最高的先執行,非剝奪

(5)優先級調度算法:根據確定的優先級選取進程/線程,每次總是選擇就緒隊列中優先級最高者運行。

(6)輪轉調度算法:每次把CPU分配給就緒隊列首進程/線程使用一個時間間隔(稱爲時間片),就緒隊列中的每個進程/線程輪流運行一個時間片。

併發進程的同步與互斥、死鎖與飢餓

進程併發性:進程的併發性是指一組進程的執行在時間上是重疊的,即一個進程執行的第一條指令是在另一個進程執行的最後一條指令完成之前開始的。其實質是一個CPU在多個進程間複用,消除計算機部件之間的互等現象以提高系統資源利用率

  • 無關併發:一組併發進程分別在不同的變量集合上操作,一個進程的執行與其他併發進程的進展無關,即一個併發進程不會改變另一個併發進程的變量值。
  • 交互併發:一組併發進程共享某些變量,一個進程的執行可能影響其他併發進程的執行結果。

併發帶來的問題

競爭CPU處理時間帶來的問題(即進程指令執行順序的先後):

  • 結果不唯一:同時處理一個共享變量導致對共享變量的操作不是原子性的
  • 永遠等待:如等待進程錯過了喚醒信號而永遠等待的情況

競爭資源帶來的問題:

  • 死鎖:兩個進程互相持有對方所需要的資源的同時又想獲取對方持有的資源從而陷入永久等待的問題
  • 飢餓:一些進程總是優先於另一些進程,使某些進程陷入長久等待

進程互斥:指若干進程要使用同一共享資源時,任何時刻最多允許一個進程使用,其他要使用該資源的進程必須等待,直到佔有資源的進程釋放該資源。

進程同步:指兩個以上進程基於某個條件協調彼此的活動,一個進程的執行依賴於協作進程的消息或信號,當一個進程沒有得到來自於協作進程的消息或信號時需等待,直到消息或信號到達才被喚醒。即同步進程間必須嚴格按照規定的某種先後次序來運行,這種先後次序依賴於要完成的特定的任務。

臨界區管理

臨界區:併發進程中與共享變量有關的程序段叫做臨界區,即一次只能有一個進程執行的程序段

臨界資源:共享變量代表的資源叫做臨界資源,不可共享資源

Peterson算法

Peterson算法是一個正確的臨界區管理算法

bool inside[2];//標誌對方進程是否進入臨界區
inside[0]=false;
inside[1]=false;
enum {0,1} turn;//標誌對方進程是否到達了臨界區前
cobegin
process P0( )
{
  inside[0]=true;//標誌該進程開始
  turn=1;
  while(inside[1]&&turn==1);//另一個進程開始但還沒有更改turn時等待,一旦更改則那個進程等待而自己執行
  {臨界區};
  inside[0]=false;
} 
process P1( )
{
inside[1]=true;
  turn=0;
  while(inside[0]&&turn==0);//等待
  {臨界區};
  inside[1]=false;
}
coend

指令是順序執行的,對於turn來說在臨界區前只有一個值,根據turn的值來判斷哪一個進程先進入臨界區,對於上述程序來說,誰先更改turn誰就先執行,先執行的進程依賴於另一個進程更改turn的值。

實現臨界區管理的硬件條件

硬件條件應該保證對於臨界區的訪問是互斥的

  • 關中斷:進程在進入臨界區之前先關中斷,退出臨界區時開中斷。雖然簡單但一般不使用,長時間關中斷會影響系統效率且並不適用於多CPU系統

  • TS指令:

    TS(x)
    {
    若x=true,則x=false;return true;
    否則 return false;
    }
    

    該指令配合外部臨界資源相當於一把鎖,進入時上鎖,退出時解鎖

    bool s=true;//臨界資源,相當於鎖
    cobegin
    process Pi( )
    { //i=1,2,...,n
    while(!TS(s));    //上鎖
    		{臨界區};
    		s=true;//解鎖
    }
    coend
    
  • 交換指令SWAP(a,b):

bool lock=false;//鎖,只有開關兩種狀態,通過SWAP保證互斥
cobegin
Process Pi( )
{//i=1,2,...,n
	bool keyi=true;
	do
      {
   		SWAP(keyi,lock);//將兩個值互換
      	}while(keyi); //上鎖
	{臨界區};
	SWAP(keyi,lock);//解鎖
}
coend

信號量與PV操作

信號量:多個進程間可以通過簡單的信號進行合作,可強迫一個進程在某個位置停止直到接收到一個特定的信號。

通常信號量的結構可以描述爲:

typedef struct semaphore
{
     int value;        //信號量值
     struct pcb *list; //信號量隊列指針
 } semaphore;

value表示可以進入臨界區的進程的數量,>0表示還可以使用的資源數量,<0則表示正在等待的進程數量。list爲指向阻塞的進程隊列指針

P操作:表示請求進入臨界區的操作:

void P(semaphore &s)
{
     s.value--;//如果<=0則直接將調用進程加入阻塞隊列
     if(s.value<0)  W(s.list); //將P操作調用者進程置爲阻塞狀態並移入s信號量隊列,轉進程調度
}

V操作:表示從臨界區出來,釋放資源的操作:

void V(semaphore &s)
{
      s.value++;
      if(s.value<=0)  R(s.list);
      //從信號量s隊列中釋放一個等待信號量s的進程並轉換成就緒態,自己則繼續執行
}

使用PV操作實現互斥的基本步驟爲

semaphore mutex;
mutex=1;
cobegin
process Pi( )
{ //i=1,…,n
	P(mutex);
	{臨界區};
	V(mutex);
}
coend

經典同步問題–哲學家進餐問題

爲了吃麪,每個哲學家必須獲得兩把叉子,且每人只能從自己左邊或右邊去取叉子。

laHGuT.png

錯誤的解決方法:

semaphore fork[5];//表示對每個叉子上鎖
for (int i=0;i<5;i++)
fork[i]=1;
cobegin
process philosopher_i( )
{ //i= 0,1,2,3,4
	while(true)
	{
		think( );
  		P(fork[i]);
	 	P(fork[(i+1)%5]);
		eat( );
  		V(fork[i]);
	 	V(fork[(i+1)%5]);
    	}
}
coend

假設5個哲學家同時執行到P(fork[i]);,相當於每個人都先拿到了左邊的叉子,再也沒有人能夠拿到右邊的叉子,導致出現了死鎖。

爲避免死鎖,可用的解決方案有:

(1)至多允許四位哲學家同時去拿左邊的叉子

因此必須新增信號量表示同時拿左邊的叉子的人數

semaphore fork[5];//表示對每個叉子上鎖
for (int i=0;i<5;i++)fork[i]=1;
semaphore count=4;//表示能夠拿到左邊1的叉子的人數
cobegin
process philosopher_i( )
{ //i= 0,1,2,3,4
	while(true)
	{
		think( );
        P(count);//相當於對count上鎖,最多同時四個哲學家能夠拿叉子
  		P(fork[i]);
	 	P(fork[(i+1)%5]);
		eat( );
  		V(fork[i]);
	 	V(fork[(i+1)%5]);
        V(count);
    	}
}
coend

(2)規定奇數號哲學家先拿他左邊的叉子,然後再去拿右邊的叉子;偶數號哲學家先拿他右邊的叉子,然後再去拿左邊的叉子

只要奇偶互相競爭,總會有一個哲學家空出來能同時拿到兩把叉子,即先進行一次兩兩配對,保證有哲學家先拿到一把叉子,再進行另一把叉子的競爭

semaphore fork[5];//表示對每個叉子上鎖
for (int i=0;i<5;i++)fork[i]=1;
cobegin
process philosopher_i( )
{ //i= 0,1,2,3,4
	while(true)
	{
		think( );
        if(i%2==0){
            P(fork[(i+1)%5]);
            P(fork[i]);
        }else{
            P(fork[i]);
            P(fork[(i+1)%5]);
        } 
		eat( );
  		V(fork[i]);
	 	V(fork[(i+1)%5]);
    	}
}
coend

(3)僅當哲學家的左右兩把叉子均可用時,才允許他拿起叉子進餐,否則一把叉子也不取:

semaphore fork[5];//表示對每個叉子上鎖
for (int i=0;i<5;i++)fork[i]=1;
semaphore mutex=1;//全局鎖
bool flag[5];
for (int i=0;i<5;i++)flag[i]=true;//true表示該叉子沒有被拿走
cobegin
process philosopher_i( )
{ //i= 0,1,2,3,4
	while(true)
	{
		think( );
        if(!flag[i]||!flag[i+1%5])continue;//只要有一把拿不到就不拿
        P(mutex);
        if(flag[i]&&flag[i+1%5]){//只有兩把叉子都能拿時才設置拿走狀態,否則就一把也不拿
            flag[i]=false;
            flag[i+1%5]=false;
            V(mutex);
        }else{
            V(mutex);
            continue;
        }
        
        if(!flag[i]&&!flag[i+1%5]){//達到正確狀態,可以直接拿左右兩把叉子
            P(fork[i]);
            P(fork[i+1%5]);
        	eat( );
  			V(fork[i]);
	 		V(fork[(i+1)%5]);
            P(mutex);//重置狀態
            flag[i]=true;
            flag[i+1%5]=true;
            V(mutex);
        }else continue;
}
coend

經典同步問題–生產者消費者問題

item B[k];
semaphore empty=k;//可以使用的空緩衝區數
semaphore full=0;//緩衝區內可以使用的產品數
semaphore mutex=1; //互斥信號量,B的鎖
int in=0;		//寫緩衝區指針
int out=0;     //讀緩衝區指針
cobegin
process producer_i( )
//生產者進程
{
  while(true)
  {	
      produce( ); 
	  P(empty); //可添加槽減一
	  P(mutex); 
	  append to B[in];//向全局資源中添加產品   
	  in=(in+1)%k;  
	  V(mutex); 
	  V(full); //可用資源加一
   }
} 
process consumer_j( )
//消費者進程
{
  while(true)
  {
	P(full);//可用資源減一
	P(mutex);
	take( ) from B[out];
	out=(out+1)%k;
	V(mutex);
	V(empty);//可添加槽加一
	consume( );
  }
}
coend

經典同步問題–讀者寫者問題

一次可以有多個讀者,但最多只能有一個寫者,讀寫不能同時進行

讀者優先解決方案:

int readcount=0;  //讀進程計數
semaphore writeblock=1;//寫鎖,一次只能有一個
semaphore mutex=1;//資源鎖
cobegin
process reader_i( )//讀者進程 
{
  	P(mutex);
 	readcount++; 	
  	if(readcount==1)  P(writeblock);//可以有多個讀者,一旦讀者進入,則寫者不能進入
	V(mutex);
  	{讀文件};
  	P(mutex);
  	readcount--;
  	if(readcount==0) V(writeblock);//沒有讀者則釋放寫鎖
   	V(mutex);
}
process writer_j( )//寫者進程
{
	P(writeblock);//上寫鎖
	{寫文件};
	V(writeblock);
}
coend

上述解決方案可能導致寫者的飢餓,爲避免寫者的飢餓,可使用寫者優先方案,在寫者想要寫時不允許讀者在進入以避免寫者的飢餓。

寫者優先方案:

int readcount=0;  //讀進程計數
semaphore readblock=1;//讀鎖,標誌是否有讀進程
int writecount=0;//寫進程技術
semaphore writeblock=1;//寫鎖,標着是否有寫進程

semaphore readmutex=1;//資源鎖,保證readcount的原子性
semaphore writemutex=1;//資源鎖,保證writecount的原子性
semaphore mutex=1;//資源鎖,讀寫資源的加鎖
cobegin
process reader_i( )//讀者進程 
{
    P(readblock);//一次只允許一個讀進程嘗試進行一次操作
    P(writeblock);//寫者優先,讀者只能先獲得寫者的鎖進行一次操作,如果寫者獲取到了,則讀者不可以在進入
  	P(readmutex);
 	readcount++; 	
  	if(readcount==1)P(mutex);//沒有寫者,讀者可以有多個
    V(readmutex);
    V(writeblock);
    V(readblock);

  	{讀文件};
    
  	P(readmutex);
  	readcount--;
  	if(readcount==0) V(mutex);//沒有讀者則釋全局資源鎖
   	V(readmutex);
}
process writer_j( )//寫者進程
{
	P(writemutex);
    writecount++;//寫者數
    if(writecount==1)P(writelock);//有寫者進來,因爲寫者優先,讀者不能進來,但是寫者可以進來
    V(writemutex);
    
    P(mutex);//寫者雖然進來了,但是還是要競爭唯一資源鎖
	{寫文件};
    V(mutex);
    
    P(writemutex);
    writecount--;
    if(writecount==0)V(writelock);//沒有寫者了,釋放寫者標誌鎖
	V(writemutex);
}
coend

經典同步問題–睡眠理髮師問題

理髮店有一位理髮師、一把理髮椅和n把椅子供顧客等候理髮休息。如果沒有顧客,理髮師便在理髮椅上睡覺。
一個顧客到來時,他必須叫醒理髮師。如果理髮師正在理髮時又有顧客到來,則如果有空椅子可坐,顧客就坐下來等待,否則離開。

int waiting=0;   //等候理髮顧客坐的椅子數
int CHAIRS=N;   //爲顧客準備的椅子數
semaphore customers=0;
semaphore barbers=0;
semaphore mutex=1;//waiting的鎖
cobegin
process barber( ) 	//理髮師進程
{
    while(true) 
    {
           P(customers);//理髮師需要顧客來進行喚醒,嘗試獲取顧客
           P(mutex);   //若有顧客時,以顧客當產品,取一個顧客消費
           waiting--;       //等候顧客數少一個
           V(barbers);    //理髮師喊一個顧客來準備爲他理髮,即理髮師可用
           V(mutex);      //退出臨界區
          cut_hair();     //理髮師正在理髮(非臨界區)
    }
}
process customer_i( ) //顧客進程
{
	P(mutex);    //進入臨界區
  	if(waiting<CHAIRS)
	{//若有空椅子,則等候顧客數加1,否則顧客離開
  		waiting++;
  		V(customers); //可用顧客數增1,即顧客可用
  		V(mutex);    //退出臨界區
  		P(barbers);  //嘗試獲取理髮師
  		get_haircut();    //否則顧客坐下理髮
  	}else V(mutex);   //人滿了,走吧!
}
coend

管程

管程是由局部於自己的若干公共變量及其說明和所有訪問這些公共變量的過程所組成的軟件模塊。將共享資源放入管程中由管程進行保護,管程確保同一時間只有一個進程進入臨界區,其餘進程進入隊列

  • 共享性:管程可被系統範圍內的進程互斥訪問,屬於共享資源
  • 安全性:管程的局部變量只能由管程的過程訪問,不允許進程或其它管程直接訪問,管程也不能訪問非局部於它的變量
  • 互斥性:多個進程對管程的訪問是互斥的。任一時刻,管程中只能有一個活躍進程
  • 封裝性:管程內的數據結構是私有的,只能在管程內使用,管程內的過程也只能使用管程內的數據結構。進程通過調用管程的過程使用臨界資源

管程的一般結構爲

  • 局部數據和條件變量組成管程內的數據結構
  • 過程/函數1~過程/函數k組成管程內的一組過程,對管程內的數據結構進行操作
  • 初始化代碼對管程內的數據結構進行初始化

管程內部的一般部件爲

  • 管程入口處的等待隊列:管程是互斥進入的,當一個進程試圖進入一個已被佔用的管程時,它需在管程入口處隊列中等待。
  • 管程內的資源等待隊列:管程是用於管理資源的,進入管程的進程等待資源時加入資源等待隊列,該隊列由條件變量維護。資源等待隊列可以有多個,每種資源一個隊列。
  • 條件變量:條件變量是管程內的一種數據結構,只有在管程中才能被訪問,它對管程內的所有過程是全局的,只能通過兩個原語操作來控制它:c.wait( )與c.signal( ),在資源隊列中阻塞或喚醒關於資源c的進程
  • 管程內的緊急等待隊列:當管程內的進程P喚醒等待隊列中的另一個進程Q時,管程中便存在兩個可運行進程。其中就緒進程需要加入就緒隊列,設置在管程中的就緒隊列稱爲緊急等待隊列。緊急等待隊列的優先級高於入口等待隊列的優先級。

條件變量與P、V操作中信號量的區別

條件變量是一種非計數信號量,維護隊列時不對其中的等待進程計數。因此在使用條件變量x時,通常需要定義一個與之配套使用的整型變量x-count用於記錄條件變量x所維護等待隊列中的進程數。而P、V操作中的計數信號量不僅維護相關隊列,還記錄隊列中進程數。

管程的一般實現

在管程內部使用PV操作完成互斥

typedef struct InterfaceModule//管程內部維護的數據結構
{
semaphore mutex1=1;//進程調用管程過程前使用的互斥信號量
semaphore next=0; //發出signal的進程掛起自己的信號量
int next_count=0;//在next上等待的進程數
};
//進入管程
void enter(InterfaceModule &IM)
{
     P(IM.mutex);//P操作進入管程
}
//退出管程
void leave(InterfaceModule &IM)
{
    if(IM.next_count>0) V(IM.next);//優先喚醒管程內緊急等待隊列中的等待進程
    else V(IM.mutex);//當管程內無等待進程時再喚醒管程外入口處的等待進程
}
//管程內部的資源等待(阻塞)操作,讓一個進程來獲取資源x_sem,自己則阻塞於x_sem等待被喚醒
void wait(semaphore&x_sem, int&x_count, InterfaceModule&IM)
{
  	x_count++;//等待資源的進程數增1,等待資源的進程將加入x_sem所管理的資源等待隊列
  	if(IM.next_count>0) V(IM.next);//等待資源的進程睡眠之前,優先喚醒管程內緊急等待隊列中的就緒進程
 	else V(IM.mutex);//若管程內緊急等待隊列空,則喚醒管程入口處等待進入管程的隊列中的進程
    P(x_sem);//喚醒其它進程之後,等待資源的進程加入x_sem所管理的資源等待隊列睡眠,下面的x_count--會暫停執行,待該進程被喚醒後再執行
    x_count--;
}
//管程內部的喚醒操作,釋放自己持有的x_sem資源並將自己阻塞於緊急等待隊列等待自己被喚醒
void signal(semaphore&x_sem, int&x_count, InterfaceModule&IM)
{
  	if x_count > 0 {//若有等待資源的進程,即x_sem資源等待隊列若有進程
    	IM.next_count++;//執行signal操作的進程將加入緊急等待隊列,因此該隊列進程數增1
    	V(x_sem);//執行signal操作的進程自己阻塞前,先釋放一個等待資源的進程	
        P(IM.next);//執行signal操作的進程進入管程內緊急等待隊列,下面的IM.next_count--暫停執行,只有進程被喚醒後纔會執行 
    	IM.next_count--;
    }
}

使用管程解決生產者消費者問題

type producer_consumer=monitor	//管程定義
{
    item B[k];     //緩衝區個數
    int in,out;    //存取指針
    int count;     //緩衝中產品數
    semaphore notfull,notempty; //條件變量
    int notfull_count,notempty_count;
    InterfaceModule IM;
   //封裝兩個生產與消費操作     
   void append(item x){
   	enter(IM);//進入管程
	if(count==k) wait(notfull,notfull_count,IM);//緩衝已滿,在notfull隊列等待空白緩衝區
	B[in]=x;
	in=(in+1)%k;
	count++; //增加一個產品
	signal(notempty,notempty_count,IM);//喚醒notempty隊列中的等待消費者,自己入緊急等待隊列
  	leave(IM);//離開管程
	}
	void take(item &x){
     	enter(IM);
		if(count==0) wait(notempty,notempty_count,IM);//在notempty隊列中等待滿緩衝區
      	x=B[out];
      	out=(out+1)%k;
      	count--;//減少一個產品
      	signal(notfull,notfull_count,IM);//喚醒notfull隊列中的等待生產者
      	leave(IM);
     }
}
cobegin
process producer_i()	//進程定義
{
	item x;
	produce(x);//生產
	producer_consumer.append(x);//追加
}
process consumer_j()
{
	item x;
	producer_consumer.take(x);//取出
	consume (x);//消費
}
coend

進程間通信

使用管道

管道是連接讀寫進程的一個共享文件,允許進程以先進先出(FCFS)方式寫入和讀出數據,並對讀寫操作進行同步。發送進程以字符流形式把大量數據送入管道尾部,接收進程從管道頭部接收數據。

ldzH7q.md.png

管道可藉助文件系統實現,包括(管道)文件的創建、打開、關閉和讀寫。

管道應互斥使用,管道讀寫不能同時進行;讀寫雙方必須能夠知道對方是否存在,只有存在才能通信;管道空間大小通常是固定的,讀寫操作時需要考慮寫滿和讀空問題。

  • 匿名管道:僅存在於內存中的臨時對象,僅用於具有共同祖先進程的父子進程或兄弟進程之間的通信。引用於內存中的臨時管道
  • 有名管道:又稱爲FIFO,具有與之關聯的文件名、目錄項和訪問權限,無親緣關係的進程可以通過引用有名管道的名字進行通信。有名管道存於外存,使用時調入內存。

使用共享內存

JVM的內存模型也使用該思想,每個線程都有自己的工作內存,存儲主內存中的變量拷貝,只能在自己的工作內存中工作,線程間無法互相訪問,只能通過主內存進行傳遞賦值。

共享內存是允許兩個或多個進程共同訪問的物理內存區域,是實現進程通信的一種手段。共享內存區映射到進程中未使用的虛地址區,以免與進程映像發生衝突。共享內存區屬於臨界資源,讀寫共享內存區的代碼屬於臨界區。

共享內存需要有標識符進行標識,第一個進程創建共享內存,其它進程則通過創建操作獲得共享內存標識符,並據此讀寫共享內存(進行系統調用創建共享內存)。通信進程將先前創建的共享內存映射到自己的虛擬地址空間,使共享內存成爲進程地址空間的一部分。通信結束時,解除共享內存到通信進程虛地址空間的映射。當所有進程不再需要共享內存時刪除共享內存。

使用消息傳遞
消息是格式化的數據,在計算機網絡中稱報文。消息由消息頭和消息體組成。

消息傳遞通信機制由信箱、發送原語(send)和接收原語(receive)組成。

  • 信箱:存放信件的存儲區域,每個信箱可分成信箱頭和信箱體兩部分。信箱頭:指出信箱容量、信件格式、信件位置指針等;信箱體:用來存放信件,可分成若干個區,每個區容納一個信件。
  • 原語send(A,信件):若信箱未滿,則把一封信件(消息)發送到信箱A,同時喚醒信件等待者進程,否則發送者阻塞。
  • 原語receive(A,信件):若信箱不空,則從信箱A接收一封信件(消息),同時喚醒等待發送者進程;否則接受者阻塞。

Linux消息隊列通信機制

Linux消息隊列通信機制屬於消息傳遞通信機制。消息隊列是內核地址空間中的內部鏈表,每個消息隊列具有唯一的標識符。消息可以順序地發送到隊列中,並以幾種不同的方式從隊列中獲取。

套接字通信

套接字(Socket)通信允許互聯的位於不同計算機上的進程之間實現通信功能。套接字用於標識和定位特定計算機上特定進程的地址,以便數據準確傳輸給目標進程。

Socket一般包含三個參數:

  • 通信的目的IP地址
  • 使用的傳輸層協議(TCP或UDP)
  • 使用的端口號

Socket的連接過程爲:

  1. 服務器監聽:服務端套接字並不定位具體的客戶端套接字,而是處於等待連接的狀態(socket→linsten)
  2. 客戶端請求:客戶端套接字提出連接請求,連接服務器端套接字(socket→connect)
  3. 連接確認:服務器端套接字監聽到客戶端套接字的連接請求時,響應請求,建立一個新的線程,把服務器端套接字的信息發送給客戶端,客戶端確認後連接即可建立(accept→send/receive message→close)

死鎖

操作系統中的死鎖是指:如果在一個進程集合中的每個進程都在等待只能由該集合中的其它進程才能引發的事件,而無限期陷入僵持的局面稱爲死鎖。

死鎖產生的四個必要條件

  • 互斥條件:進程互斥使用資源,一旦某個資源被佔用,欲使用該資源的進程必須等待
  • 佔有和等待條件:進程申請新資源得不到滿足而等待時,不釋放已佔有資源
  • 不剝奪條件:一個進程不能搶奪其它進程佔有的資源
  • 循環等待條件:存在一組進程循環等待資源的現象。該條件是上述三個條件可能引發的結果,前三個都是必要條件

只要破壞這四個條件之一,死鎖就可防止

死鎖的防止

死鎖防止通過破壞產生死鎖的四個條件之一來實現

  • 破壞互斥條件:使資源可同時訪問而不是互斥使用。該辦法對於磁盤適用,對於磁帶機、打印機等多數資源不僅不能破壞互斥使用條件,還要加以保證,因此一般不這麼做。
  • 破壞佔有和等待條件:靜態分配可以破壞佔有和等待條件。靜態分配是指一個進程必須在執行前就申請它所需要的全部資源,並且直到它所需要的資源都得到滿足後纔開始執行。但是這樣資源利用率低。
  • 破壞不剝奪條件:即採用剝奪式調度方法。當進程申請資源未獲准許時,在等待前主動釋放資源。剝奪調度方法目前只適用於內存資源和處理器資源。
  • 破壞循環等待條件:採用層次分配策略可以破壞循環等待條件。層次分配策略將資源被分成多個層次,進程按照由低到高的層次順序申請和得到資源,按照由高到低的層次順序釋放資源。當進程得到某一層的一個資源後,如果需要申請該層的另一個資源,則必須先釋放該層中的已佔資源(即對於可能產生死鎖的資源進行分層次管理確保其不會有兩個進程互相拿到而不釋放)。

死鎖的避免
死鎖避免方法允許系統中同時存在死鎖的三個必要條件,即互斥、佔有且等待和非搶佔;
每當進程提出資源申請時,系統分析滿足該資源請求時系統是否會發生死鎖,若不會發生則實施分配,否則拒絕分配。

避免死鎖的銀行家算法

問題描述:

一個銀行家擁有資金M,被N個客戶共享,銀行家對客戶提出下列約束條件:

(1)每個客戶必須預先說明自己所要求的最大資金量;

(2)每個客戶每次提出部分資金量申請和獲得分配;

(3)如果銀行滿足了客戶對資金的最大需求量,則客戶在資金運作後一定可以很快歸還資金。

在上述問題中,銀行家就是操作系統;資金就是系統資源;客戶就是進程

銀行家算法的步驟爲:

(1)系統中的所有進程進入進程集合

(2)在安全狀態下對進程請求的資源進行試探性分配

(3)系統用剩餘的可用資源和進程集合中其它進程還要的資源數作比較,找到剩餘資源能滿足最大需求量的進程A,保證A運行完畢並歸還全部資源

(4)把進程A從集合中去掉,相當於回收其資源。如果進程集合非空,則返回(2)

(5)若進程集合爲空,則系統處於安全狀態,可實施本次分配;否則,系統處於不安全狀態,本次資源分配暫不實施,申請進程等待

銀行家算法缺乏實用價值:很難在進程運行前知道其所需的資源最大量;同時算法要求系統中的進程必須是無關的,相互間沒有同步要求;並且進程的個數和分配的資源數目應該是固定的。資源總是會動態變化的,預先分配的方案會導致資源利用率降低

死鎖的檢測

系統定時運行一個“死鎖檢測”程序,如果檢測到系統發生了死鎖,再採取措施解除它。

進行死鎖檢測時,系統維護一個進程-資源圖,進程-資源分配圖是描述進程和資源間申請與分配關係的一種有向圖,由進程結點P、資源結點R和有向邊組成,可用以檢測系統是否處於死鎖狀態。

  • 請求邊:從進程指向資源的有向邊Pi→Rj爲請求邊,表示進程Pi申請資源類Rj中的一個資源。
  • 分配邊:從資源指向進程的有向邊Rj→Pi爲分配邊,表示Rj類中的一個資源已分配給進程Pi。
lwKLp4.png

死鎖在邏輯上的判定可由下圖說明(前提是進程間互相不孤立):

lwQjdx.md.png

死鎖解除

(1)立即結束所有進程的執行,並重新啓動操作系統。以前工作全部作廢,損失可能很大。

(2)剝奪陷於死鎖的進程佔用的資源,但並不撤銷它,直至死鎖解除。

(3)撤銷陷於死鎖的所有進程,解除死鎖繼續運行。

(4)逐個撤銷陷於死鎖的進程,回收其資源,直至死鎖解除。

(5)根據系統保存的檢查點,使所有進程回退,直到足以解除死鎖。

(6)當檢測到死鎖時,如果存在某些未捲入死鎖的進程,且它們會進一步建立一些新的抑制進程能執行到結束,則它們可能釋放足夠的資源來解除死鎖。

存儲管理

即OS對於內存與外存的管理

基礎概念

  • 地址重定位/地址變換:在執行程序時,將其中的邏輯地址轉變爲物理地址的過程。
  • 邏輯地址:邏輯地址是與程序在內存中的物理位置無關的訪問地址。在執行對內存的訪問之前必須把邏輯地址轉換爲物理地址。
  • 物理地址:物理地址是程序運行時中央處理器實際訪問的內存單元地址。
  • 相對地址:相對地址是邏輯地址的一個特例,是相對於已知點(通常是程序的開始處)的存儲單元的地址。

靜態重定位與動態重定位

靜態重定位:根據程序所裝入的內存位置由裝入程序依據重定位信息一次性將程序中所有的邏輯地址轉變爲物理地址,然後程序開始執行,這種重定位方式稱爲靜態重定位。靜態重定位無須硬件支持,易於實現,但靜態重定位不允許程序在內存中移動位置。

動態重定位:地址轉換工作穿插在指令執行的過程中,每執行一條指令,CPU對指令中涉及的邏輯地址進行轉換,這種重定位方式稱爲動態重定位。動態重定位必須藉助硬件地址轉換機構實現,動態重定位允許程序在內存中移動位置。

存儲保護

  • 地址越界保護:對進程執行時所產生的所有主存訪問地址進行檢查,確保進程僅訪問自己的主存區。各道程序只能訪問自己的主存區而不能跳轉到另一個進程中,尤其不能訪問操作系統的任何部分。
  • 信息存取保護:進程訪問分配給自己的主存區時,系統要對訪問權限進行檢查,如檢查是否允許讀、寫、執行等,從而確保數據的安全性和完整性,防止有意無意的誤操作而破壞主存信息。

連續存儲管理

連續存儲管理對每個進程分配一個連續的存儲區域。

固定分區存儲管理

固定分區存儲管理將內存空間劃分爲若干個位置和大小固定的連續區域,每一個連續區域稱爲一個分區,各分區大小可相同,也可不同。每當進程進來時都直接分配一個可用的分區給它。

缺點很明顯:

(1)分區數目和大小在系統啓動階段已經確定,限制了系統中活動進程的數目,也限制了當前分區方案下可運行的最大進程。

(2)當分區長度大於其中進程長度時,造成存儲空間浪費。

固定分區會產生內部碎片。內部碎片:由於進程所在分區大於進程大小而造成的分區內部浪費部分稱爲內部碎片。

可變(動態)分區存儲管理

按照作業的大小劃分分區,劃分的時間、大小和位置都是動態的,屬於一種動態分區方法。

每當進程進入時,系統根據當前內存狀況動態分配一塊分區給它。隨着時間的推移,會產生很多外部碎片。外部碎片:**內存中的小到難以利用的分區,這種分區稱爲外部碎片。**可使用壓縮技術合併外部碎片,但不相鄰空閒分區的移動合併消耗CPU大量時間

夥伴系統
也稱爲buddy算法,是固定分區和可變分區折中的主存管理算法,由Knuth在1973年提出。夥伴系統採用稱爲夥伴的可以分割、合併的不同規格的內存塊作爲分區單位。利用二叉樹結構進行內存分區的劃分。

夥伴:兩個大小相等且由同一個尺寸爲2i的空閒塊分割而來的內存塊互爲夥伴。

分配:運用夥伴系統分配內存空間的過程是一個對空閒內存區不斷對半切分,直到切分出的內存塊爲大於或等於進程大小的最小夥伴爲止的過程。

回收:夥伴系統回收內存的過程是不斷將相鄰空閒夥伴合併爲更大夥伴單位,直到夥伴不空閒,無法合併爲止的過程。

lwJGJP.md.png

分頁存儲管理

分頁存儲管理將全部內存劃分爲長度相等的若干份,每一份稱爲一個物理塊或頁框。

作業自動被分頁系統劃分爲與每個物理塊相等的若干等份,每一份稱爲一頁或一個頁面。

使用分頁存儲時,一個作業的任一頁可以裝入到內存任一空閒物理塊,並不要求邏輯上相鄰的頁所在內存物理塊也相鄰。此時,邏輯地址結構=頁號+頁內位移;物理地址結構=物理塊號+塊內位移
4KB32220212(4KB) 若頁面大小設置爲4KB,地址總線寬度爲32位,則頁號爲2^{20},業內位移爲2^{12}(4KB)
由邏輯地址映射物理地址,物理塊號=頁號,物理塊內位移=業內位移

操作系統需爲每個作業建立一張頁表,頁表用於實現地址變換,頁表記載了邏輯地址到物理地址的對應關係,系統通過頁表可以準確訪問內存中屬於一個作業的所有頁面。

lwd0wF.md.png

例題:若頁面大小設置爲4KB,地址總線寬度爲32位,則頁內位移位數爲12位,頁號位數=32-12=20,邏輯地址60000在第幾頁?頁內偏移是多少?若該頁被裝進物理塊1280中,則物理地址是多少?
60000=(0000EA60)16,1653=(E)16,=(A60)16 60000=(0000EA60)_{16},16進制中,前5位爲頁號,後3位爲頁偏移。頁號=(E)_{16},頁內偏移=(A60)_{16}。

1280=(500)16,=(00500A60)16 物理地址同理,物理塊號爲1280=(500)_{16},物理偏移=頁偏移,則物理地址爲(00500A60)_{16}

快表

引入快表的原因是CPU每存取一個指令/數據時,需要兩次訪問內存

lwwXg1.md.png

快表同樣使用緩衝的思想以加快速度。爲了減少分頁存儲管理系統中的內存訪問速度下降一倍問題,在存儲管理部件中增設一個專用的高速緩衝存儲器,用來存放最近訪問過的部分頁表項,這種高速緩衝存儲器稱爲快表或聯想存儲器。

有了快表,根據頁號查找對應的物理塊號時,首先查找快表中的局部頁表,若找到則將物理塊號和頁內地址(也就是偏移地址)拼接形成物理地址,根據該物理地址訪問相應的內存單元。若在快表中未找到物理塊號,則再查找內存頁表,獲取物理塊號一方面形成物理地址,另一方面將該表項抄到快表中,以備下次再次訪問該頁面時從快表中獲得物理塊號。查快表和查內存頁表是同時進行的,一旦從快表中找到了對應項,則立即停止對內存頁表的查找。

lw0KUg.md.png

多級頁表

如果頁表很大,頁表佔用的內存物理塊也允許是離散的,而且頁表也可以按需裝入內存,這樣就需要再建立頁表的頁表,即頁目錄,這就是二級頁表機制。需要的還可建立更多級的頁表。無論多少級頁表頂級頁表必須完全駐留內存。

在二級頁表中,頁目錄表是一級頁表,頁表頁是二級頁表,其邏輯地址就變爲:頁目錄號(一級頁表號)+頁號(二級頁表號)+頁內位移。其實就是個一對多、一對一的映射

分段存儲管理

分段存儲管理以段爲單位進行存儲分配,作業每一段被分配一個連續的主存空間,各段存儲位置不一定相鄰,各段大小不一。即將程序進行分段,由OS維護進程段表,其邏輯地址=段號+段內位移。

由段號查找進程段表,獲取起始位,物理地址=起始位+偏移量(段內位移)

lwyV76.md.png
16KB32218214 若段長最大爲16KB,計算機地址總線爲32位,則段號最多2^{18},段內位移最多2^{14}
例題:若段長最大爲16KB,計算機地址總線爲32位,邏輯地址60000在第幾段?段內偏移是多少?若該段被裝進物理起始地址1280中,則該邏輯地址對應的物理地址是多少?
60000=(EA60)16=(1110101001100000)20 60000=(EA60)_{16}=(1110 1010 0110 0000)_2(前導0省略)
前18位爲段號,即佔第三段,後14位爲段內偏移,即
10101001100000=(2A60)16 10 1010 0110 0000= (2A60)_{16}
物理地址=物理起始地址(由段號查找段表而來)+段內偏移,即
1280=(500)16=(500)16+(2A60)16=(2F60)16 1280=(500)_{16},物理地址=(500)_{16}+(2A60)_{16}=(2F60)_{16}
分段地址是二維的,即必須先將程序分段,分配段號與段偏移,再根據段號從段表中去查找物理起始地址,加上段偏移地址獲得真正物理地址。

虛擬存儲管理

也就是虛存管理。虛擬內存指加載進程進入內存時只加載進程運行所必須的幾個塊(頁/段),需要時再進行I/O,以提供給用戶看起來多的內存空間。以時間換空間,以較小的內存空間運行大的進程或較多的進程將消耗較多的進程對換時間。

局部性原理

在一段時間內,程序訪問的存儲空間僅限於某個區域(這稱爲空間局部性),或者最近訪問過的程序代碼和數據很快會再次被訪問(這稱爲時間局部性)。局部性原理描述了進程中程序和數據的集簇傾向,表明虛擬內存方案是可行的。

虛擬內存的分頁式管理

在進程開始運行之前,裝入全部頁面集合中的一個或幾個頁面,進程運行過程中,訪問的頁面不在內存時,再裝入所需頁面;若內存空間已滿,而又需要裝入新的頁面時,則根據某種算法淘汰某個頁面,以便裝入新的頁面。

缺頁中斷與普通中斷的區別

(1)普通中斷在兩條指令之間纔會響應;缺頁中斷涉及的指令在執行期間就需要響應缺頁中斷。
(2)當指令本身或者指令所處理的數據跨頁時,在執行一條指令的過程中可能發生多次缺頁中斷。

缺頁中斷的處理過程

  1. 掛起請求缺頁的進程
  2. 根據頁號查外頁表,找到該頁存放的磁盤物理地址
  3. 查看主存是否有空閒頁框,如有則找出一個,修改主存管理表和相應頁表項內容,轉步6
  4. 如主存中無空閒頁框,則按替換算法選擇淘汰頁面,檢查它是否曾被寫過或修改過,沒有修改則轉步6
  5. 該淘汰頁面被寫過或修改過,則把它的內容寫回磁盤原先位置
  6. 進行調頁,把頁面裝入主存所分配的頁框中,同時修改進程頁表項
  7. 返回進程斷點,重新啓動被中斷的指令

總的來說,處理過程爲:①查看內存是否有空閒物理塊,如有則裝入頁面到空閒物理塊,同時修改頁表相應項以及內存分配表②如果內存中沒有空閒物理塊,則按替換算法選擇一個頁面淘汰,若該頁面被寫過或修改過,則寫回外存;否則只簡單淘汰該頁面。淘汰頁面之後要修改頁表相應項,然後調入頁面到淘汰頁面釋放的物理塊中

缺頁中斷率:對於進程P的一個長度爲A的頁面訪問序列,如果進程P在運行中發生缺頁中斷的次數爲F,則f = F/A稱爲缺頁中斷率。

抖動(顛簸):在請求分頁虛擬存儲管理系統中,剛被淘汰的頁面立即又要訪問,而調入不久即被淘汰,淘汰不久再被調入,如此反覆,使得系統的頁面調度非常頻繁,以致大部分時間消耗在頁面調度上,而不是執行計算任務,這種現象稱爲“抖動”(或者顛簸)。

虛擬內存的分段式管理

對於程序來說有兩種分配方式:

  • 固定分配:固定分配使進程在生命週期中保持固定數目的頁框(即物理塊)。進程創建時,根據進程類型和程序員的要求決定頁框數。
  • 可變分配:進程分得的頁框數可變。進程執行的某階段缺頁率較高,說明目前局部性較差,系統可多分些頁框以降低缺頁率,反之說明進程目前的局部性較好,可減少分給進程的頁框數

頁面淘汰算法

(1)最佳頁面淘汰算法(OPT)

調入一頁而必須淘汰一箇舊頁時,所淘汰的頁是以後不再訪問的頁或距現在最長時間後再訪問的頁。OPT是邏輯上的理想算法,實際上不可能實現。
OPT是可用於衡量各種具體算法的標準

(2)先進先出頁面淘汰算法(FIFO)

先進先出頁面淘汰算法總是淘汰最先調入主存的那一頁,或者說在主存中駐留時間最長的那一頁(常駐的除外)。

(3)最近最久未使用頁面淘汰算法(LRU)

淘汰的頁面是在最近一段時間裏較久未被訪問的那一頁

維護一個棧,每當命中時就將命中的頁放到棧尾,每當缺頁時就替換掉棧頂的頁並將換進來的頁放到棧尾

(4)時鐘頁面替換算法

①頁面首次裝入主存時其“引用位”置1

②主存中的任何頁面被訪問時,“引用位”置1

③淘汰頁面時,從指針當前指向的頁面開始掃描循環隊列,把遇到的“引用位”是1的頁面的“引用位”清0,跳過這個頁面;把所遇到的“引用位”是0的頁面淘汰掉並換進來新的頁,指針推進一步

④掃描完循環隊列,若未淘汰任何頁,則再次掃描

設備管理

基礎概念

設備類別

從數據交換單位來分可分爲塊設備與字符設備

  • 塊設備:塊設備將信息存儲在固定大小的塊中,並且每個塊都有地址,因此可獨立尋址。所有傳輸以一個或多個完整的塊爲單位。硬盤、CD-ROM和USB盤是最常見的塊設備。
  • 字符設備:字符設備以字節爲單位發送或接收一個字符流,且不可尋址。鍵盤、打印機、鼠標、網絡接口,以及大多數與磁盤不同的設備都可以看做字符設備。

從設備訪問方式來分可分爲順序設備與隨機設備:

  • 順序設備:順序設備上數據的邏輯順序與物理存儲順序保持一致。
  • 隨機設備:隨機設備上數據的邏輯順序與物理存儲順序可以不一致。

I/O控制方式

(1)輪詢

輪詢也稱爲忙等待,CPU向設備下達操作命令後,不斷查詢設備操作完成狀態。在輪詢控制方式下,CPU與設備的工作完全是串行(順序)的,而不是併發的。

l0pGNt.md.png

(2)中斷控制

中斷控制下,CPU向設備發出讀寫命令後,不再查詢設備執行狀態,轉而執行其它計算任務。當設備完成讀寫操作後以中斷的方式主動向CPU報告完成情況。CPU響應中斷執行一箇中斷處理程序,將設備從外界獲得的數據取走放到內存或者相反。

l0pwuQ.md.png

(3)DMA直接存儲器訪問

DMA(直接存儲器訪問)方式允許I/O設備與內存之間直接交換一個連續的信息塊,在傳輸期間無需CPU的干預,而是由專用處理器–DMA控制器完成具體傳輸控制操作。

在開始DMA傳輸時,CPU對DMA芯片進行設置,說明需要傳送的字節數、有關的設備和內存地址以及操作方向,接着啓動DMA。當DMA芯片完成設備I/O時,引發一箇中斷。在控制設備傳輸期間,DMA挪用指令週期,控制總線,CPU暫時不能訪問內存。週期挪用會減少CPU計算時間,但是,DMA對CPU時間的佔用遠少於輪詢方式中的循環檢測和中斷方式中的中斷處理程序執行開銷。DMA將設備I/O中斷CPU的頻率由字節中斷降低爲塊中斷,即每傳送一個連續的信息塊才中斷CPU一次。

l0pqgO.md.png

(4)通道

通道也叫輸入輸出處理器,是獨立於CPU專門負責數據輸入/輸出傳輸工作的處理機,能執行自己的指令程序,代替CPU完成複雜的輸入/輸出操作,完成主存和外圍設備間的信息傳送,與CPU並行操作。

在通道方式下,當進程需要執行I/O操作時,CPU只需啓動通道,即可返回執行其它進程,通道則執行通道程序,對I/O操作進行控制。

一個CPU可以連接若干通道,一個通道可以連接若干控制器,一個控制器可以連接若干臺設備。

I/O通道與CPU的主要區別

(1)通道指令類型單一,主要侷限於與I/O操作有關的指令。
(2)通道所執行的通道程序是放在主機內存中的,因此,通道與CPU共享內存。這樣,通道與CPU對內存的使用是分時的。

I/O軟件系統

所謂I/O軟件系統,就是要對硬件設備進行分層抽象,將I/O軟件組織成層次結構,低層軟件屏蔽硬件細節,高層軟件提供簡潔、友好的界面。設計I/O軟件系統時要考慮的主要問題有:

  • 設備無關性:屏蔽設備的具體細節,向高層提供抽象的邏輯設備,並完成邏輯設備和具體物理設備的映射
  • 出錯處理:儘可能在接近硬件的層面處理錯誤。低層軟件能夠處理的硬件I/O錯誤不要讓高層軟件感知
  • 同步(阻塞)/異步(中斷驅動)傳輸:進程在啓動設備執行I/O操作後可繼續執行其它工作,直至中斷到達,稱爲異步傳輸;如果進程在啓動設備後便被掛起,稱爲同步傳輸
  • 緩衝技術:建立數據緩衝區使數據的到達率和離去率相匹配

分爲四個層次:用戶空間的I/O軟件、設備無關I/O軟件、設備驅動程序、中斷處理程序

設備驅動程序

每類設備控制器都是不同的,需要不同的軟件進行控制。專門與控制器對話,發出命令並接收響應的軟件稱爲設備驅動程序。

由於設備供多個進程共享,進程對設備的訪問必須由操作系統仲裁,因此,設備驅動程序通常必須是操作系統內核的一部分。如果添加了一個新設備,該設備的驅動程序必須安裝到操作系統內核中。

設備驅動程序的功能是接收設備無關軟件的抽象讀寫請求,並監視請求的執行,以及設備初始化、對電源需求和日誌事件進行管理。

設備驅動程序的典型工作過程如下爲:驅動程序啓動時要檢查輸入參數是否有效,若無效則返回錯誤信息,否則將抽象請求中的抽象參數轉換爲物理參數。接着,驅動程序檢查設備當前是否正在使用。如果正在使用,請求被加入等待隊列,否則啓動設備開始處理請求。驅動程序依次將所需命令寫入設備控制器寄存器,依次執行。

設備無關I/O軟件

設備無關I/O軟件的基本功能是執行所有設備公共的I/O功能,並向用戶層軟件提供統一的接口。主要功能包括:

  1. 爲設備驅動程序提供統一接口,實現設備名到驅動程序的映射和設備保護功能
  2. 進行緩衝管理,緩衝使得數據傳輸成批進行,而不是按字或按字節進行,節約操作時間。
  3. 輸出錯誤報告。I/O錯誤很常見,許多錯誤必須由適當的驅動程序來處理,設備無關軟件提供錯誤處理框架。
  4. 分配與釋放設備:某些設備必須互斥使用,例如CD-ROM刻錄機。申請使用該類設備的進程可能會被拒絕或者排隊等候。
  5. 提供與設備無關的塊尺寸,不同磁盤的扇區大小可能不同,設備無關軟件隱藏這一事實並向高層軟件提供一個統一的塊大小。

磁盤管理

磁盤由若干個塗有磁性介質的圓形盤面構成,經過低級格式化,每個盤面(包括正反兩面)被劃分成一系列同心圓,每個同心圓稱爲一個磁道,每個磁道再劃分爲若干等份,稱爲扇區,數據就以扇區爲存儲單位保存在磁盤上。扇區是磁盤訪問的基本單位,訪問扇區的某些字節意味着訪問整個扇區。所有盤面上同等大小的磁道構成柱面

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-XTNxKcax-1578144306486)(https://s2.ax1x.com/2020/01/04/l0Arsf.md.png)]

磁盤塊物理地址:訪問磁盤上的數據時需要給出物理塊(扇區)的物理存儲地址,該地址是三維的,採用(柱面號,磁頭號,扇區號)表示。

磁盤塊邏輯地址:磁盤物理塊(扇區)的邏輯地址是一維線性的,稱爲邏輯塊號(扇區號)。所有扇區依次排列,從0開始連續編號。扇區編排順序是自外向裏對各個柱面內的扇區排序,同一柱面內的各個扇區先按磁道順序、再按磁道內扇區順序排列。

訪問扇區時,可以給出邏輯塊號,系統自動將邏輯塊號轉換爲(柱面號,磁頭號,扇區號)構成的三維物理地址。

磁盤調度算法

讀寫一個磁盤塊時,影響其訪問的時間因素主要有三個方面:

  • 尋道時間:磁頭移動到指定磁道所需時間
  • 旋轉延遲時間:等待指定扇區到達磁頭下的旋轉時間
  • 數據傳輸時間:數據在磁盤與內存之間的傳輸時間

當多個磁盤I/O請求到來時,磁盤驅動程序需要安排I/O請求的處理順序,這稱爲磁盤調度或移臂調度。

  • 先來先服務算法(FCFS):先來先服務算法根據磁道訪問請求到來的先後順序完成請求。
  • 最短尋道時間優先算法(SSTF):最短尋道時間優先算法總是優先滿足距離磁頭當前位置最近的訪問請求。
  • 電梯調度算法:對於先後到達的磁盤訪問請求,電梯調度算法首先選擇移臂方向,磁臂在該方向上移動的過程中依次處理途經的各個訪問請求,直到該方向上再無請求時,改變移臂方向,依次處理相反方向上遇到的各個請求。
  • 循環掃描算法(C-SCAN):在該算法中,磁頭僅在一個移動方向上提供訪問服務。磁臂從磁盤開始端柱面至結束端柱面移動的過程中依次處理途經請求,然後,直接返回開始端柱面重復進行,歸途中並不響應請求。開始端與結束端柱面構成了一個循環。
  • N步掃描算法:N步掃描算法將磁盤請求隊列分成若干個長度爲N的子隊列,磁盤調度按先來先服務算法依次處理這些隊列。

虛擬設備

爲了提高設備利用率,尤其是提高獨佔設備的利用率,減少作業週轉時間,系統利用共享設備模擬獨佔設備的功能,使得獨佔設備成爲能夠共享的設備,這就是設備虛擬。SPOOLing(同時外圍操作,假脫機技術)就是一種具體的設備虛擬技術。

SPOOLing是對脫機輸入/輸出系統的模擬。該技術利用一類物理設備模擬另一類物理設備,使獨佔設備變成可共享設備。

實例

在聯機方式下,打印機正在打印一個作業時,其它打印請求必須等待。
在脫機方式下,進程的打印請求不是等待提交給打印機,而是提交到磁盤緩衝區中保存起來,進程即可返回執行其它計算任務。真正的打印動作待打印機空閒時,由專門的打印進程取出各個作業逐個打印。

當用戶進程請求打印輸出時,SPOOLing並不立即把打印機分配給它,只是做兩件事:
(1)輸出進程在輸出井中爲該進程申請一個空閒磁盤塊區,將要打印的數據送入其中;
(2)輸出進程再爲用戶進程申請一張空白的用戶請求打印表,將用戶的打印要求填入其中,再將該表掛到請求打印隊列上。
打印機空閒時,輸出進程從請求打印隊列隊首取出一張請求打印表,根據其中的要求將要打印的數據從輸出井送到內存緩衝區,再由打印機打印。
打印完成後,SPOOLing再取出下一張請求打印表,打印下一組數據,直到請求打印隊列爲空時,輸出進程阻塞;當有新的打印請求到來時被喚醒。

文件管理

文件與目錄

文件:文件是記錄在外存上具有名稱的相關信息的集合。文件是對存儲設備的抽象,它將以存儲介質物理塊爲單位的信息存儲單元抽象爲以文件爲單位的邏輯存儲單元。完成物理到邏輯上的映射,從而向用戶提供一個簡單的外存信息訪問接口。

文件屬性

  • 基本屬性:包括文件名和擴展名、標識符、文件屬主ID、文件所屬組ID等
  • 類型屬性:表明文件類型。如普通文件、目錄文件、系統文件、隱式文件、設備文件、pipe文件、 socket文件等;ASCII碼文件、二進制文件等
  • 控制屬性:包括文件的位置信息、邏輯記錄長、文件當前長、文件最大長、關鍵字位置、關鍵字長度、文件打開次數等。
  • 管理屬性:包括文件創建時間、最後訪問時間、最後修改時間等,用於保護、安全和使用跟蹤。
  • 保護屬性:包括用戶對文件允許執行的訪問操作,如可讀、可寫、可執行、可更新、可刪除等;上鎖標誌和解鎖標誌;口令等;許可訪問者。

文件內容訪問方式

  • 順序訪問:順序訪問從文件開頭順序讀取文件的全部字節或記錄,不能跳過某一些內容,文件後面的內容不能先於文件前面部分的內容讀取出來。寫入與此類似。後面的訪問起點依賴於前面訪問後確定的文件指針位置。
  • 隨機訪問(直接訪問):能夠以任意次序讀取其中字節或記錄的文件稱爲隨機存取文件或直接訪問文件。數據庫系統使用的文件往往屬於隨機存取文件。磁盤文件可以直接訪問,因爲磁盤訪問可以指定物理塊地址。
  • 索引訪問:索引訪問建立在直接訪問方式上。索引訪問需要爲文件創建索引,這樣的文件稱爲索引文件。索引類似文件內容目錄,包含指向各內容塊的指針。查找索引文件時,首先查找索引塊,獲得目標內容塊的指針,再從目標內容塊中找到所需記錄。

目錄:目錄是查找文件的實體,用於幫助查找文件

目錄提供了訪問文件的入口,每個文件在目錄表中都有一個目錄項(文件控制塊FCB),目錄項用於記載文件的屬性信息,如名稱、位置、大小和類型等

全部目錄項也可構成文件,稱爲目錄文件。目錄文件非空,至少包含當前目錄項和父目錄項。文件目錄的作用是將邏輯名轉換爲物理名,即將文件名轉換爲文件的磁盤地址。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-eQOGuSQ6-1578144306487)(https://s2.ax1x.com/2020/01/04/l0m1bV.md.png)]

層次目錄系統允許用戶創建多級目錄,各級目錄形成樹型結構,也稱爲目錄樹。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-J99CU54D-1578144306488)(https://s2.ax1x.com/2020/01/04/l0mfKI.md.png)]

文件結構

文件邏輯結構

文件的邏輯結構是從用戶角度看到的反映一定邏輯意義的文件內容組成單位及各部分之間的關係。

  • 流式文件(無結構文件):流式文件將文件內容看做字節流,即整個文件由一個字節流組成。這種看法忽略了可能存在的文件內在的邏輯結構,實際上將文件看成是無結構的。大多數現代操作系統對用戶僅僅提供流式文件。
  • 記錄式文件(有結構文件):記錄式文件是一種有結構的文件,包含若干邏輯記錄。邏輯記錄是文件中按信息的邏輯含意劃分的信息單位。記錄式文件是數據庫管理系統支持的基本文件類型

文件物理結構

文件的物理結構是指文件內容及其各部分之間邏輯關係在物理存儲空間中的存儲和實現方法。這時文件看作物理文件,是相關物理塊的集合。

構造文件物理結構的實質是建立邏輯記錄與其物理存儲位置之間的對應關係。主要有兩種方法:

  • 計算法:利用哈希函數等設計映射算法,建立邏輯記錄到物理記錄地址之間的映射關係,以記錄鍵的計算結果作爲對應的物理塊地址。直接尋址文件、計算尋址文件、順序文件均採用計算法構造。
  • 指針法(鏈表法):指針法以鏈表形式反映各記錄的物理地址及各記錄之間的邏輯順序關係。索引文件、索引順序文件、連接文件等均採用指針法構造。

文件空間管理

內存管理已經說過了,此處的文件空間管理主要是指對文件外存(即磁盤塊)的管理。

文件空間管理不僅需要分配並記錄存放文件的磁盤塊,還需要記錄空閒磁盤塊的情況。

文件空間分配方法

實際上就是給文件分配磁盤塊的方法

(1)連續分配

給文件分配一個連續的物理塊,OS需要登記各個空閒區的位置和大小以供分配使用。因此前提是OS必須事先知道文件長度才能分配,同時對文件的修改、插入、增加會變得困難,適用於已知長度且不需要經常修改的情況,如光盤刻錄。

(2)鏈接分配

給文件分配物理上不連續的物理塊,但是每個物理塊有一個指向下一塊的指針,因此邏輯上文件是連續的(實際上就是鏈表了)

(3)索引分配

爲每個文件都建立一張索引表,也就是一個map,文件包含索引塊地址,由索引塊地址找到索引表,索引表內順序存儲了該文件的物理塊地址

(4)多級索引分配

當索引塊很多時,索引表也變得較大,因此使用多級索引分配。

在頂級索引表中,前幾項直接指向物理塊,稱爲直接尋址;後幾項劃爲多個部分,分別是一級、二級、三級……等多級索引,一級索引項指向一個新的索引表,在該索引表中的索引項直接指向物理塊,稱爲一次間接尋址;二級索引項指向一個二級索引表,該索引表的索引項又指向一個索引表,這個索引表的索引項才指向一個實際的物理塊,稱爲二次間接尋址……以此類推

文件外存管理

也就是要記錄空閒塊的數量和位置

  • 位示圖(位向量或字位映象表):系統中的每個盤塊採用一個二進制位(0或1)表示該盤塊是否空閒。分配和回收時只需修改二進制位值即可。
  • 空閒塊鏈:空閒塊鏈方法將所有空閒塊鏈接在一起,形成一個鏈表。
  • 空閒區表:一個空閒區由若干位置連續的空閒盤塊構成。空閒區表爲外存上的所有空閒區建立一張空閒表,每個空閒區佔一個表項,表項內容包括空閒塊位置和連續空閒的塊數。
  • 成組空閒塊鏈:將空閒盤快分成固定的組進行管理。舉個例子:UNIX/Linux將系統中的所有空閒盤塊分成若干組,每組100個盤塊,每組第一塊登記下一組空閒塊的盤物理塊號和空閒總數,形成成組空閒塊鏈。訪問成組空閒塊鏈進行分配操作時,每次僅需裝入其中的一組到內存,待該組中登記的盤塊分配完畢後,再從外存裝入下一組空閒盤塊列表到內存。回收空閒盤塊時,將空閒盤塊號登記在位於內存的空閒盤塊列表中,僅當該表滿(達到100)時,將其加入成組空閒塊鏈中並寫回外存,然後在內存中建立一個新的盤塊組並加入成組空閒塊鏈中。

l0MwWD.md.png

當分配49個空閒塊出去時:

l0Qy3F.md.png

此時要是再分配一個空閒塊則先將300#的內容複製到專用管理塊filesys中,然後再將300#分配出去

l01aF0.md.png

問題

1.進程輪流使用處理器與多個打印任務共享打印機的區別。

進程輪流使用處理器屬於同時共享、資源分時複用,也叫併發共享,併發進程釋放處理器時,其任務通常並未結束。多個進程可以同時使用處理器。
多個打印任務共享打印機屬於資源的互斥共享,也叫順序共享,在一個打印任務結束之前,另一個打印任務不能開始。即多個打印任務不能同時使用打印機。

2.資源虛化與資源抽象的區別

(1)資源虛化強調從邏輯上擴充資源數量。
(2)資源抽象強調封裝、隱藏軟硬件內部細節,簡化資源應用接口。

3.併發性、並行性與順序性的區別

(1)併發性是指多個事件或活動在同一時間段內(一個時間段)開始或者說發生,注意不是完成或者結束。
(2)並行性是指多個事件或活動在同一時刻(一個時間點)開始或者說發生,注意不是完成或者結束。
(3)順序性是指一個事件或活動結束前,另一個事件或活動不可以開始。在任何一個時刻或者時間段內,只會有一個事件或活動在進行。其它事件或活動要麼已經結束,要麼尚未開始。

4.說明特權指令、處理器狀態、程序狀態字寄存器之間的關係

(1)處理器指令系統分爲特權指令和非特權指令,處理器狀態分爲用戶態和核心態。程序狀態字寄存器記錄有處理器狀態信息。
(2)特權指令在覈心態下執行,中斷是處理器由用戶態切換到核心態的唯一途徑。特權指令與系統共享資源的分配和使用相關。當多個進程競爭公共資源時,其仲裁權在於操作系統。
因此,特權指令的執行權在於操作系統。操作系統向用戶提供了大量爲其使用公共資源服務的系統調用處理程序。用戶程序通過執行訪管中斷可以委託操作系統爲其提供公共資源服務。
在用戶態下執行特權指令是非法的,引起中斷後,系統會捕捉到這種非法操作並中止其執行。

5.剝奪調度與非剝奪調度和中斷的關係

(1)剝奪調度:在進程自身未出現等待事件的情況下,由於時間片用完或者出現了優先級更高的進程而被迫讓出處理器。
(2)非剝奪調度:一旦獲得處理器,只有進程自身出現等待事件時纔會讓出處理器。
(3)無論剝奪調度還是非剝奪調度,進程都有可能出現等待事件而中斷,讓出處理器。

6.虛擬存儲器大小有什麼限制?

虛擬存儲器是利用外存的一部分(對換區),通過在內外存之間對換進程,從邏輯上擴充內存容量。
外存容量遠大於內存容量,但能夠用來擴充內存容量的外存僅是其中的一小部分,因爲虛擬存儲器的容量受地址總線寬度的制約。地址總線寬度決定了程序可訪問的最大地址空間,超過該空間的存儲區或者說地址是無法訪問的。
虛存受到地址總線寬度的制約,因此即使理論上虛存可以無限大,但是實際上同時最多能用的也還是內存大小,只不過使用虛存可以通過I/O來回換數據,速度將低了很多

7.DMA與中斷的區別

DMA 傳送方式與程序中斷對CPU的干擾程度不同。程序中斷請求不但使CPU停下來,而且還要CPU執行中斷服務程序,需要完成斷點和處理器現場保護和CPU與外設之間的數據傳送工作,消耗CPU較多時間。
DMA請求僅僅使CPU暫停一下,該暫停不屬於中斷,不需要執行中斷處理程序,不需保存斷點和處理器現場信息。DMA挪用CPU指令週期控制外設與主存之間的數據傳送,無需CPU的干預。
DMA與CPU交替控制總線,交替執行指令和數據傳輸工作。在整個數據塊傳輸結束時,DMA才向CPU發中斷信號,CPU執行中斷處理程序。

8.SPOOLing系統的虛擬設備原理

SPOOLing系統即假脫機系統。將原來以聯機方式使用的獨佔設備改造成爲脫機使用的虛擬共享設備。
在聯機方式下,每個需要設備I/O的進程排隊等待向設備提交輸入輸出作業。
在SPOOLing系統中,每個需要設備I/O的進程並不直接向設備提交輸入輸出作業,也不控制設備操作,而是向SPOOLing系統提交輸入輸出作業,SPOOLing系統再向設備提交作業。SPOOLing系統類似於批處理系統中的操作員。

9.虛擬文件系統的原理是什麼,體現了什麼資源管理技術思想?

(1)虛擬文件系統(VFS)定義了一個代表不特定文件系統通用特徵和行爲的文件模型。
VFS抽象出所有文件系統的公共部分,形成一個簡單、統一的抽象文件系統接口提供給用戶。
用戶僅通過抽象文件系統接口層表達文件操作意圖,文件操作的具體執行則由底層的實際文件系統來完成。
從抽象文件系統到某一具體文件系統的轉換工作由映射模塊完成。
(2)虛擬文件系統體現了資源抽象的資源管理技術思想。不同文件系統有着不同的實現方法和細節,虛擬文件系統則封裝、隱藏了各種具體文件系統的細節差異,使得用戶僅需面對一種統一的、抽象的文件系統,即虛擬文件系統,簡化了用戶對文件系統的學習和使用。

參考

《操作系統原理與Linux實踐教程》申豐山 王黎明 著

《操作系統——精髓與設計原理》William Stallings 著

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章