《現代操作系統1~6》總結
Lyle
2011-8-25
一. 操作系統概論
一般計算機系統包含硬件、系統程序和應用程序三個部分。粗略地講,系統程序中最重要的操作系統,它夾在硬件和應用程序之間,其任務就是有效地管理計算機各種資源,使得使用計算機變得“簡單”。說簡單是因為操作系統作為裸機的擴展,提供給用戶人性化一點的抽象。這些所謂的抽象包括進程和線程、地址空間和文件。
基礎的硬件有:處理器、存儲器、I/O設備和總線。
操作系統有多種,這裡主要學的是單CPU操作系統基本原理,這對學習其他高級操作系統是很有幫助的。所以下面的內容幾乎都是假設只有單個CPU的操作系統,除非做特殊說明。
二. 進程與線程
2.1進程
操作系統是用一張進程表(結構數組)來實現進程的。
書上最精闢的一句話:“進程是正在運行程序的一個抽象/實例。”這句話看出進程和程序的一點差別:前者是動態的而後者是靜態的。
一般CPU采用的是“流水線”作業,只不過CPU在各個進程之間來回切換的速度極快,所以給人一種“并行”的偽現象。
系統資源是有限的,所以進程是有生命周期的,具體包括進程創建和進程死亡。在UNIX系統中是有進程層次(父子關係),而在Windows中由於句柄(令牌)的作用所以所有的進程都是對等的。
進程有三個可能的狀態:1運行、2阻塞和3就緒。但只有四種轉換關係:1->2,等待輸入;2->3,有有效輸入;3->1,選擇這個進程;1->3,選擇另一個進程。
上面狀態的轉化關係“3->1”和“1->3”是由進程調度程序引起的。之所以要調度,還是那個原因,資源(CPU)是有限的。一個好的調度算法可以使得資源更有效地被利用。調度算法有FIFO(先進先出)、RR(輪換)和HPF(优先级)等,不同環境如批處理、交互式和實時系統有不同的調度算法。
2.2進程間通信
進程間通信是通過進程間通信原語來實現的,如下面提到的信號量、管程或消息。
但凡有共享資源的情況,就有可能潛在“競爭條件”,從而發生錯誤或者死鎖(deadlock),進程們也是一樣的。爲了避免進程的競爭條件,實現多個進程讀寫共享資源的互斥(mutual exclusion),引進臨界區(critical section)的概念。當一個進程在更新共享資源的時候,其他進程不會進入其臨界區。實現互斥的思路有多種,屏蔽中斷、鎖變量和嚴格輪換法等因為可能違反互斥條件而被拋棄,而把鎖變量和警告變量相結合的Perterson算法、需要硬件支持的TSL算法以及它的變體XCHG算法都是正確的,可是儘管正確,他們卻有忙等待的缺點。忙等待算法不僅浪費CPU時間,而且可能產生優先級反轉問題。
用sleep-wakeup思想來實現互斥算法。1965年Dijkstra提出信號量(semaphore)的概念,對信號量的操作是down(大於零減一)和up(加一),它們通常都作為系統調用實現,這樣在進行屏蔽中斷的時候產生的時間副作用是幾乎沒有的。用信號量來解決有界緩衝區(bound buffer)問題:需要full、empty和mutex這三個信號量。信號量的一個簡化版本是互斥量(mutex),其簡易性適用於管理小段代碼。
用管程(monitor)來實現進程的互斥。管程是由過程、變量和數據結構等組成的一個集合。管程相當于圍墻,把共享的資源和對其進行操作的進程圍起來,其他進程要訪問該資源就得經過管程,從而實現了互斥。
消息傳遞(message passing)也可以解決互斥問題。使用send和receive這兩個系統調用,從而比管程要方便一點,也比信號量高級一點。
屏障(barrier)是一種用於進程組的同步機制。
2.3 線程
線程是一種輕量級的進程!線程是進程中的一個實體!
線程不像進程,它不擁有系統資源,但它可與同屬於一個進程的其他兄弟線程共享全部資源。線程調度以及線程間的通信幾乎和進程是一樣的。其中有一點區別,那就是多個進程有多個線程的時候,存在層次上的調度,這時的線程調度取決于是用戶級線程還是內核級線程或者兩者都支持。
引入線程的原因有:(1)一個程序可能有多個可以同時進行活動,那么把程序分解成多個準并行的線程,會使得程序設計模型變得簡單;(2)線程比進程量級輕,所以容易創建與撤銷;(3)基於計算密集型+I/O密集型的考慮;(4)多CPU情況。
三. 死鎖
通俗地講,所謂資源死鎖,是兩個或兩個以上進程因爭奪資源而出現互相等待的現象,若不假借外力的情況下進程都無法執行下去。
3.1 資源
這裡講的資源是一種排他性的對象,可以是硬件設備,也可以是一組信息。“簡單地說,資源就是隨著時間的推移,必須能夠獲得、使用以及釋放的任何東西。”
資源分為可搶占的(如存儲器)和不可搶占的(如CD刻錄機),因前者而產生的死鎖通常可以通過重新分配資源而化解,所以死鎖一般和不可搶占資源有關。
資源的獲取可以通過信號量或者互斥量來實現。
3.2 資源死鎖概述
Coffman等人總結了發生資源死鎖的四個必要條件:(1)互斥條件;(2)占有和等待條件;(3)不可搶占條件;(4)環路等待條件。
處理死鎖的四種策略:
1)忽略之(“鴕鳥算法”)。仁者見仁智者見智,但總歸不是好的方法。
2)檢測死鎖并恢復。采用現有資源向量和資源分配矩陣,通過基於向量的比較的算法來檢測死鎖的存在;假設成功地檢測到死鎖,可以通過諸如“利用搶占資源”、“利用回滾策略”和“殺死進程”的手段進行恢復。
3)細心地進行資源分配,避免死鎖。此法需要事先獲得一些特定的信息,在動態分配資源的過程中通過某種方法防止系統處於不安全狀態。1965年Dijkstra提出“銀行家算法”來防止系統進入不安全狀態,但這種算法是不太實用的。
4)通過破壞上面死鎖的四個必要條件之一來防止死鎖。分別用“使用spooling printer”、“在開始就請求全部資源”、“搶占資源”和“對資源按序編號”來處理四個必要條件。
3.3 死鎖其他
嚴格地講,死鎖不都因為爭奪資源而引起,所以上面所述都叫“資源死鎖”,除此之外還有一種網絡上的“通信死鎖”,產生的條件為進程集合中的進程都在等待集合中其他的進程引發的事件,這裡沒有涉及資源,該定義同樣適合於資源死鎖。很多時候我們可以設置適當的超時機制來處理通信死鎖。
活鎖是指進程集合中的進程爲了影響集合中其他進程的變化而持續改變自己的狀態,但不做有用功。活鎖可能飢餓而死,但可以通過先到先服務粗略來避免。
四. 存儲器管理
早期的計算機沒有存儲器抽象,而現在的計算機幾乎都有,其原因在於:若沒有存儲器抽象,物理地址暴露給進程可能會導致系統崩潰,而且想要實現多進程也是困難的。
4.1 地址空間
為使內存中的多個程序互不影響,需要考慮保護和重定位這兩個問題。為此提出了地址空間的概念,它是應用程序的一種對內存的抽象。“地址空間是一個進程可用於尋址內存的一套地址集合。”早期的一個簡單的為進程分配地址空間的方法是動態重定位,即簡單地把每個進程的地址空間映射到物理內存的不同位置而已,例如CDC6600和Intel8088使用基址寄存器和界限寄存器。但這種方法由於重定位中的加法運算而會使得機器變慢,所以現在基本棄用。
有兩種處理內存超載的通用方法:(1)交換技術,間歇地把進程掉入內存和存回磁盤。(2)虛擬內存。
交換技術是一種動態分配內存的方法,位圖和空閒鏈錶是兩種跟蹤內存使用的方式,這和圖的表示方法是類似的。但交換技術始終不是一個好的方法,因為軟件膨脹的關係。
4.2 虛擬內存
程序是越來越大的,想要把好幾G的程序完全放入內存似乎是不太現實的,因此把程序分割成許多片段,運行時只把需要的小片段放入內存中,稱為覆蓋技術。
“虛擬內存的基本思想是:每個程序擁有自己的地址空間,這個空間被分割成多個塊,每個塊稱作一頁或頁面(page)。每一頁有連續的地址空間。這些頁被映射到物理內存,但并不是所有的頁都必須在內存中才能運行程序。當程序引用到一部分在物理內存中的地址空間時,由硬件立刻執行必要的映射。當程序引用到一部分不在物理內存中的地址空間時,由操作系統負責將缺失的部分裝入物理內存并重新執行失敗的指令。”(書上原話,足夠精煉)
分頁存儲管理。
內存空間與頁相同大小的若干存儲塊,稱為物理塊或頁框。為進程分配內存時是以塊為單位將進程中的若干頁分別裝入多個可不相鄰接的塊中。分頁存儲管理的地址結構是由邏輯地址和物理地址組成的,邏輯地址=“頁號+偏移量”,而物理地址=“頁框號+偏移量”。一個程序有一張頁表,頁表結構為“頁號+塊號”。建立快表是提高效率的好方法,也就是把頁表的活躍部分區別對待。當發生缺頁中斷時,就經常需要置換內存中的頁面,因此一個好的頁面置換算法是個關鍵。置換算法有“最優頁面置換算法”、“最近未使用頁面置換算法”、“先進先出頁面置換算法”、“第二次機會頁面置換算法”、“時鐘頁面置換算法”、“最近最少使用頁面置換算法”、“老化算法”、“工作集頁面置換算法”、“工作集時鐘頁面置換算法”等,其中最好的兩種是基於LRU的老化算法和基於工作集的工作集時鐘算法。
分段存儲管理。
段的長度因程序而異,其結構為“段號+段內地址”。分段能使程序模塊化處理以及處理變化的數據結構變得簡單,但缺點是管理困難。段與頁是有明顯區別的:前者是邏輯單位,目的是滿足用戶需求,且大小不固定而取決于用戶程序,其地址空間是二維的;後者是物理單位,目的是提高內存使用率,且大小固定由系統確定,其地址空間是一維的。
最好的方式是分段與分頁的結合!這樣的機構為“段號+段內頁號+頁內地址”。
五. 文件系統
5.1 文件
文件是對磁盤存儲的一種抽象,其本質類似于地址空間。
文件的命名依賴于所處的系統。文件的結構常見的有三種,第一種是字節序列,如UNIX、MS-DOS和Windows;第二種是記錄序列,現在已經棄用;第三種是樹,這在一些處理商業數據的大型機上廣泛使用。
文件的類型一般有普通文件(regular file)和目錄(directory)。普通文件又分為ASCII文件和二進制文件。而目錄是分層次分級的,對應的有路徑名和一些目錄操作。
文件屬性是指除了文件名和數據之外其他與文件有關的信息,如日期時間大小等。
文件操作如create、delete、open等等是爲了便於文件的存儲和檢索。
5.2 文件系統的實現
多數磁盤被劃分為一個或多個分區,每個分區有一個獨立的文件系統,其中0好扇區稱為主引導記錄(MBR),用來引導計算機。下面是一個示意圖
(參考文獻1中的插圖)
文件實現。系統為文件分配磁盤塊的方法常見的有:(1)連續分配。簡單,並且操作性能好;但磁盤利用率低。一開始受歡迎,接著受冷落,最後因為一次性寫光學介質的出現有重新受到青睞。(2)鏈錶分配。這種的話文件檢索很慢。(3)在內存中采用表的鏈錶分配。這是基於內存中的文件分配表(FAT)來實現的,但內存有限,故此法對於大磁盤是不合適的。(4)給每個文件賦予一個稱為i節點(index-node)的數據結構,其中列出文件屬性和文件塊的磁盤地址。此法較好。
目錄實現。Windows采用簡單目錄,包含固定大小帶有磁盤地址和屬性的目錄項。UNIX采用每個目錄項只引用i節點的目錄。
文件共享。文件系統是一個DAG,因此文件共享是很方便的。
虛擬文件系統(VFS)。將多個文件系統統一成一個有序的框架,其關鍵思想是抽象出所有文件系統中共同的部分然後將這部分東西單獨放在一層。很流行。
5.3 文件系統的管理和優化
磁盤空間管理。涉及文件塊大小的確定,以及如何記錄空閒的磁盤塊,和磁盤配額等問題。
文件系統備份。需要考慮時間和空間、價值、動態數據、安全等問題。
文件系統性能。常用的優化方法有:(1)高速緩存。(2)塊提前讀。(3)減少磁盤臂運動。
磁盤碎片整理。
六. 輸入輸出
6.1 I/O硬件原理
I/O設備大致分為塊設備(block device)和字符設備(character device)這兩種。前者把信息存儲在固定大小的塊中,而且每個塊都有自己的地址,如硬盤、CD-ROM和USB盤等。後者以字符為單位發送或接收一個字符流,是不可尋址的,如打印機、網絡接口、鼠標等。而時鐘卻兩者都不是,但這是極個別,所以上面的分類大致還是滿意的。
I/O設備一般由機械的和電子的部件組成,其中電子部件稱作設備控制器或適配器。
CPU與設備控制寄存器和數據緩衝區進行通信的方法有兩種:(1)為每個寄存器分配一個I/O端口號;(2)將所有寄存器映射到內存空間中,具有這種方法的系統稱為內存映射I/O(memory-mapped I/O)。這兩種方法各有優缺點。
直接存儲器存取(DMA)方案使得CPU尋址設備控制器并與它們交換數據更為有效。
中斷的機構如圖所示:
(參考文獻1中的插圖)
6.2 I/O軟件原理
I/O軟件設計的目標:設備獨立性(device independence)、統一命名(uniform naming)、錯誤處理(error handling)、同步(synchronous)(=阻塞)和異步(asynchronous)(=中斷驅動)傳輸、緩衝(buffering)等。
I/O實現的三個不同方式:(1)程序控制I/O。CPU完成全部工作。(2)中斷驅動I/O。(3)使用DMA的I/O。
6.3 I/O軟件層次
有四個層次,他們是從底層往上排序的:(1)中斷處理程序;(2)設備驅動程序;(3)與設備無關的I/O軟件;(4)用戶空間的I/O軟件。
6.4 實際的I/O設備
盤:磁盤,RAID,CD-ROM,可刻錄CD,可重寫CD,DVD等。
時鐘。
鍵盤、鼠標、監視器。
電源。
瘦客戶機:有潛力。
七. 總結
結束了兩個多星期間歇性的學習,學的是經典的操作系統原理。主要了解了三個抽象:進程、地址空間和文件,它們構成了操作系統最核心的概念。之外要有死鎖這個有趣的東西,以及各種I/O設備。有些概念還是比較晦澀難懂,希望在以後的學習中加深理解。
雖說不要寫成摘錄的形式,不過這部分內容剛接觸而且概念性很強,有時候不得不引用書中精煉的話,而且不少是目錄的匯總。有點失敗~~
參考文獻:
[1] Andrew S. Tanenbaum:Modern Operating System (2nd edition)