[翻譯] Operating System-There Easy Pieces 4.進程的抽象

進程的抽象

在本文中,咱們將討論操做系統爲用戶提供的最基本的抽象之一:進程。 非正式地定義一個進程很是簡單:它是一個正在運行的程序。程序自己是一個沒有生命的東西:它只是存儲在磁盤上的一堆指令(也許還有一些靜態數據),等待開始行動。 操做系統採用這些字節並使它們運行,將程序轉換爲有用的東西。算法

事實證實,人們常常想要同時運行多個程序; 例如,您可能但願在筆記本或者PC上同時運行Web瀏覽器,郵件程序,遊戲,音樂播放器等應用。 事實上,典型的系統彷佛能夠同時運行數十甚至數百個進程。 這樣作使系統易於使用,不須要關心CPU是否可用,只須要運行程序就行。 所以咱們存在的挑戰是:shell

問題的關鍵:數組

如何提供許多CPUS的錯覺?瀏覽器

雖然只有少數物理CPU可用,但操做系統如何提供幾乎無窮無盡的CPU供應的錯覺?網絡

 

操做系統經過虛擬化CPU來建立這種錯覺。經過運行一個進程,而後中止它並運行另外一個進程,這樣一直輪換執行,操做系統能夠製造出存在許多虛擬CPU的錯覺。而實際上只有一個物理CPU(或少數幾個)。這種基本技術稱爲CPU的時間共享(時間片),容許用戶運行任意數量的併發進程。潛在的成本是性能損耗,由於若是必須共享CPU,每一個進程都會運行得更慢。數據結構

爲了更好的實現CPU的虛擬化,操做系統既須要一些低級措施,也須要一些高級策略。咱們稱這些低級措施爲「機制」。機制是實現所需功能的低級功能的方法或協議。例如,咱們將在下面學習如何實現上下文切換,這使操做系統可以中止運行一個程序並在給定的CPU上開始運行另外一個程序。全部現代操做系統都採用這種分時機制。併發

除了這些機制以外,還以策略的形式存在操做系統中的一些智能算法。策略是在OS中作出某種決定的算法。例如,給定在CPU上運行的許多可能的程序,OS應該運行哪一個程序?操做系統中的調度策略將作出此決定,可能使用歷史信息(例如,哪一個程序在最後一分鐘運行得更多?),工做負載知識(例如,運行的程序類型)和性能指標(例如,系統是否優化交互性能或吞吐量?)來作出決定。函數

 

提示:使用時間共享(和空間共享)性能

時間共享是操做系統共享資源的最基本技術之一。 經過容許資源被一個實體使用一段時間,而後稍微使用另外一個實體,等等,所討論的資源(例如,CPU或網絡連接)能夠被許多人共享。 時間共享的天然對應物是空間共享,其中資源在但願使用它的人之間被劃分(在空間中)。 例如,磁盤空間天然是空間共享資源,由於一旦將塊分配給文件,在用戶刪除它以前不可能將其分配給另外一個文件。學習

 

4.1 進程的抽象

運行的程序在操做系統中的抽象咱們稱之爲進程。如上所述,一個進程就是一個正在運行的程序。在任什麼時候刻,咱們均可以經過對其在執行過程當中訪問或影響的系統的不一樣部分進行清點來總結一個過程。

爲了理解流進程的構成,咱們必須瞭解其機器狀態:程序在運行時能夠讀取或更新的內容。在任何給定時間,機器的哪些部分對執行該程序很重要?

包含進程的機器狀態的一個明顯組成部分是其存儲器。指令存在內存中,運行程序讀寫的數據也在內存中。所以,進程能夠尋址的內存(稱爲其地址空間)是進程的一部分。

進程的機器狀態的一部分是寄存器。許多指令明確地讀取或更新寄存器,所以它們對於執行過程很重要。

請注意,有一些特殊的寄存器構成了這種機器狀態的一部分。例如,程序計數器(PC)(有時稱爲指令指針或IP)告訴咱們當前正在執行哪一個程序指令。相似地,堆棧指針和相關的幀指針用於管理函數參數,局部變量和返回地址的堆棧。

最後,程序一般也訪問持久存儲設備。此類I / O信息可能包括進程當前打開的文件列表。

 

提示:單獨的政策和機制

在許多操做系統中,常見的設計範式是將高級策略與其低級機制分離[L + 75]。 您能夠將機制視爲提供有關係統問題的答案; 例如,操做系統如何執行上下文切換? 該政策爲哪一個問題提供了答案; 例如,操做系統如今應該運行哪一個進程? 將二者分開能夠很容易地改變策略,而沒必要從新考慮該機制,所以是一種模塊形式,通常的軟件設計原則。

 

4.2 進程API

雖然咱們將實際流程API的討論推遲到後續章節,但在這裏咱們先了解一些操做系統的最基本的接口。這些API以某種形式可用於任何現代操做系統。

 

creat:一個操做系統必須包含一些建立新進程的方法。在shell中鍵入命令時,或雙擊應用程序圖標,調用操做系統以建立一個新進程來運行您指定的程序。

destory因爲存在用於建立流程的接口,所以系統還提供了強制銷燬進程的接口。固然,許多進程都會運行完成後自行退出。可是,當他們不這樣作時,用戶可能但願殺死他們,所以中止失控進程的接口很是有用。

wait:有時等待進程中止運行是有用的。所以常常提供某種等待接口。

Miscellaneous Control:除了殺死或等待進程以外,有時還有其餘可能的控制。例如,大多數操做系統提供某種方法來暫停進程(阻止它運行一段時間)而後恢復它(繼續運行)。

Status:一般還有接口來獲取有關進程的狀態信息,例如運行的時間或狀態。

 

 

4.3 進程建立的一些細節

咱們應該揭露的一個謎團是一個程序是如何變成進程的?具體來講,操做系統如何啓動並運行程序?進程建立過程實際上如何運做?

操做系統運行程序必須作的第一件事是將其代碼和任何靜態數據(例如,初始化的變量)加載到進程的地址空間中。程序最初以某種可執行格式駐留在磁盤上(如今大都是基於閃存的SSD)。所以,將程序和靜態數據加載到內存中的過程須要操做系統從磁盤讀取這些字節並將它們放在內存中(如圖4.1所示)。

在早期(或簡單)操做系統中,加載過程是在運行程序以前完成的,即一次完成。現代操做系統懶惰地執行該過程,即,僅在程序執行期間須要加載代碼或數據。要真正瞭解代碼和數據的延遲加載是如何工做的,您必須更多地瞭解分頁和交換的機制,咱們將在討論內存虛擬化時討論這些主題。如今,請記住,在運行任何操做以前,操做系統顯然必須作一些工做才能將重要的程序位從磁盤放入內存。

 

一旦將代碼和靜態數據加載到內存中,操做系統在運行該進程以前還須要執行一些其餘操做。必須爲程序的運行時堆棧(或只是堆棧)分配一些內存。正如您可能已經知道的那樣,C程序將堆棧用於存放局部變量,函數參數和返回地址。操做系統分配此內存並將其提供給進程。操做系統也可能會經過參數初始化堆棧。具體來講就是,堆棧中會保存main()函數的參數,即argc和argv數組。

操做系統還能夠爲程序的堆建立一些初始內存。在C程序中,堆用於顯式請求的動態分配數據。程序經過調用malloc()來請求這樣的空間,並經過調用free()顯式釋放它。數據結構須要堆,例如鏈表,哈希表,樹和其餘有趣的數據結構。堆最初會很小;當程序運行,並經過malloc()庫API請求更多內存時,操做系統可能會進入內核併爲進程分配更多內存以幫助知足此類調用。操做系統還會執行一些其餘初始化任務,尤爲是與輸入/輸出(I / O)相關的任務。例如,在UNIX系統中,默認狀況下每一個進程都有三個打開的​​文件描述符,用於標準輸入,輸出和錯誤。這些描述符使程序能夠輕鬆地從終端讀取輸入以及將輸出打印到屏幕。咱們將在本書的第三部分中詳細介紹有關持久性的I / O,文件描述符等內容。

經過將代碼和靜態數據加載到內存中,經過建立和初始化堆棧,以及經過執行與I / O設置相關的其餘工做,操做系統如今(最終)爲程序執行設置了作好了鋪墊。而後它還有一個最後的任務:跳轉到在入口點去運行程序,即main()。經過跳轉到main()例程(經過咱們將在下一章討論的專用機制),OS將CPU的控制權轉移到新建立的進程,從而程序開始執行。

 

4.4 進程狀態

如今咱們已經知道一個進程是什麼(雖然咱們將繼續改進這個概念),而且(大體)知道如何建立它,讓咱們談談一個過進程在給定時間能夠處於的不一樣狀態。 在早期的計算機系統中出現了一個進程可能處於這些狀態之一的概念。 在簡化視圖中,進程能夠處於如下三種狀態之一:

•正在運行(running):在運行狀態下,進程正在處理器上運行。 這意味着它正在執行指令。

•就緒(ready):在就緒狀態下,一個進程已準備好運行,但出於某種緣由,操做系統不選擇在此時刻運行它。

•阻塞(blocked):在阻塞狀態下,進程已執行某種操做,使其在其餘事件發生以前沒法繼續運行。 一個常見示例:當進程向磁盤發起I / O請求時,它會被阻塞,而後其餘一些進程可使用該處理器。

Figure 4.2: Process: State Transitions

若是咱們將這些狀態映射到圖表,咱們將到達圖4.2中的圖表。 正如您在圖中看到的那樣,能夠根據操做系統的判斷在準備狀態和運行狀態之間移動進程。 從準備運行到運行意味着該過程已被計劃; 從運行轉移到準備就緒意味着該過程已被取消預約。 一旦進程被阻塞(例如,經過啓動I / O操做),OS將保持這樣直到某些事件發生(例如,I / O完成); 此時,進程再次進入就緒狀態(若是OS決定,可能會當即再次運行)。

 

4.5 數據結構

操做系統是一個程序,與任何程序同樣,它有一些跟蹤各類相關信息的關鍵數據構。例如,爲了跟蹤每一個進程的狀態,操做系統可能會爲全部準備好的進程保留某種進程表,以及跟蹤當前正在運行的進程的一些附加信息。操做系統還必須以某種方式跟蹤被阻止的進程。當I / O事件完成時,操做系統應確保喚醒正確的進程並準備好再次運行。

圖4.3顯示了操做系統須要跟蹤xv6內核[CK + 08]中每一個進程的信息類型。相似的過程結構存在於「真實」操做系統中,例如Linux,Mac OS X或Windows。查看它們,看看它們有多複雜。

從圖中,您能夠看到操做系統跟蹤流程的幾個重要信息。對於已中止的進程,寄存器區域(PCB中的字段)將保持其寄存器的內容。當進程中止時,其寄存器將保存到該存儲單元。經過恢復這些寄存器(即將它們的值放回實際的物理寄存器中),操做系統能夠恢復運行該過程。咱們將在之後的章節中詳細瞭解這種稱爲上下文切換的技術。

*Figure 4.3: The xv6 Proc Structure

您還能夠從圖中看到,除了運行,準備和阻塞以外,還有一些其餘狀態能夠進入。 有時,系統中會有處於剛建立的初始狀態的進程。 此外,能夠將進程置於已退出但還沒有清除的最終狀態(在基於UNIX的系統中,這稱爲殭屍狀態)。 這個最終狀態可能頗有用,由於它容許其餘進程(一般是建立進程的父進程)檢查進程的返回代碼,看看它是否已成功執行成功。(一般在基於UNIX的系統中,程序執行成功會返回零,不然非零)。 完成後,父進程將進行最後一次調用(例如,wait())以等待子進程完成,並向操做系統代表它能夠清理任何涉及該進程的相關數據結構 - 滅絕過程。


 

ASIDE:數據結構 - 進程列表

操做系統充滿了各類重要的數據結構,咱們將在這些對應的章節討論。 進程列表是第一個這樣的結構,並且是其中比較簡單的一個。固然任何可以同時運行多個程序的操做系統都會有相似於這種結構的東西,以便跟蹤系統中全部正在運行的程序。 有時人們會將存儲過程信息的個體結構稱爲過程控制塊(PCB),這是一種討論包含每一個進程信息的C結構的奇特方式。


 

4.6 總結

咱們介紹了操做系統最基本的抽象:進程。 它被簡單地視爲一個正在運行的程序。 考慮到這一律念性觀點,咱們如今將繼續討論實質性過程:實施進程所需的低層機制,以及以智能方式安排進程所需的更高層次的策略。 經過結合機制和策略,咱們將創建對操做系統如何虛擬化CPU的理解。

相關文章
相關標籤/搜索