進程描述和控制(os 筆記二)
進程描述和控制
? 計算機最初的主要任務之一就是高效的自動化我們的工作,完成用戶交付的任務。而這種任務在計算機中的表示就是一個個的進程。從上一篇文章中描述的計算機的發展歷史我們能發現,無論是單道批處理系統還是多道批處理系統,操作系統的目的都是圍繞對進程的控制和調度,從而實現執行用戶任務。因此,系統必須滿足的大多數操作都涉及進程。而為了 控制進程,操作系統必須為每一個進程 維護一個數據結構,這個數據結構描述進程的狀態和資源的所有權。
什麽是進程
1、定義
- 正在執行的程序
- 正在計算機上執行的程序程序實例
- 能分配給處理器並由處理器執行的實體
- 一組指令序列的執行、一個當前狀態和相關的系統資源集
進程的兩個基本元素是程序代碼和相關聯的數據集。
2、進程控制塊
進程控制塊 是由操作系統創建和管理的具有一個進程充分信息的數據結構。通過使用進程控制塊,操作系統可以透明的中斷和恢復一個進程。它是操作系統能夠支持多進程和提供多處理的關鍵工具。
進程控制塊通常包括以下內容:
- 標識符
- 狀態
- 優先級
- 程序計數器:程序中即將被執行的下一條指令的地址
- 內存指針:包括程序代碼和進程相關數據的指針,還有和其他進程共享內存塊的指針
- 上下文數據:進程執行時處理器的寄存器中的數據(用於恢復執行)
- I/O 狀態信息
- 記賬信息
現在,可以認為一個進程是由代碼段,數據段和進程控制塊組成。
進程狀態
? 操作系統的基本職責就是控制進程的執行,這包括確定交替執行的方式和給進程分配資源。在設計控制進程的程序時,第一步就是描述進程所表現出的行為。
1、兩狀態進程模型
? 通過觀察可知,一個進程可以處於兩種狀態,運行和未運行,所以可以構造最簡單的進程狀態模型,只有兩個狀態,運行態和未運行態。由於多道程序設計的原因,一個程序在未結束前將會在這兩個狀態之間進行切換。之後隨著更多因素的加入,模型將會變得更為具體。
兩狀態進程模型將維護一個 FIFO 隊列,其中保存未在運行的進程的數據結構。分派程序(監控程序的一部分)每次從中選擇一個進程執行。
2、進程的創建和終止
進程的創建
當一個進程添加到那些正在被管理的進程集合中去時,操作系統需要建立用於管理該進程的數據結構(之後介紹),並在內存中給他分配地址空間。
導致進程被創建的條件:
- 新建的批處理作業
- 交互登錄
- 操作系統因為提供一項服務而創建
- 由現有的進程派生
導致進程被結束的原因:
正常完成
超過時限
運行錯誤
- 無可用內存
- 越界
- 算數溢出
- 指令錯誤
等
父進程終止
操作員或系統幹涉
父進程請求子進程結束
?
3、五狀態模型
? 兩狀態模型中的待執行隊列采用先進先出的方式(不考慮優先級)從未運行的進程中選擇下一個被執行的進程。但是這種模型是不合適的。當隊列中有正在等待事件的被阻塞的進程時,這個進程可能會因為不能執行而再次被放回隊尾,等到他解除阻塞時,他可能排在了新加入進程的後面,所以這種策略不會每次選擇在隊列中存在時間最久的進程。為解決這種情況的一種比較自然的方法是將未運行狀態分成兩個狀態:就緒態 和 阻塞態。另外還可以增加兩個有用的狀態,新建態和退出態。
狀態圖:
五種狀態:
- 運行態
- 就緒態:進程做好了準備,有機會就開始執行
- 阻塞/等待態:進程在某些事件發生前不能執行,比如 I/O 操作完成
- 新建態:剛剛創建的進程,操作系統還沒有把他加入到可執行進程組中。通常是進程控制塊已經創建但是還沒有加載到內存中的新進程
- 退出態:操作系統從可執行進程組中釋放出的進程,或自身停止,或者是因為某種原因被取消
基於新的模型的新的進程隊列:
采用這種模型,分派器每次不在是采用先進先出的方式從就緒隊列中選取進程,而是搜索整個就緒隊列,查找在隊列中未被阻塞且等待時間最久的進程來執行。
多級隊列
? 對於之前簡單的例子,上圖給出了各個狀態的轉化關系。基於這種模型,系統會維護兩個隊列。一個為就緒進程隊列,另一個為阻塞進程隊列。當操作系統打算選擇一個進程運行時,便從就緒進程隊列中選取一個執行。相應的,阻塞隊列放置正在等待事件的被阻塞的進程。當一個事件發生時,所有等待該事件的處於阻塞中的進程都被轉換到就緒隊列中。這種方案意味著,如果一個事件發生,那麽操作系統必須搜索整個阻塞隊列來尋找等待這個事件的進程。在大型操作系統中,隊列中可能有幾百個甚至幾千個進程,因此擁有多個隊列將會很有效,一個事件可以對用一個隊列。
被掛起的進程
交換的需要
現在在之前模型的基礎上考慮再加入一種新的狀態——掛起態。
事實證明加入這一狀態是很有必要的。暫時假設操作系統未采用虛擬內存技術,由於 CPU 速度比 I/O 快很多,所以很常見的一種情況是所有的進程都已經執行到了等待 I/O 的指令並處於阻塞狀態,此時內存中全部是阻塞中的進程而沒有可執行的進程,CPU 因此處於空閑狀態(降低了計算機效率)。
一種解決方案是采用更大的內存以裝載更多的進程從而盡量避免這種情況的發生,但是這種方案有兩種缺陷。首先是內存的價格在達到兆和千兆位後價格會隨之增加。另一方面是,程序對內存空間需求的增長速度要比內存價格下降的速度要塊。因此,更大的內存往往導致更大的進程,而不是更多的進程。
另一種解決方案是采用__交換__,將內存中某一進程的一部分或者全部移動到磁盤中,並維護一個掛起隊列,從而使內存空間有更多的空余以容納新的進程加入。
新加入的狀態
? 當操作系統已經執行了一個掛起操作,此時內存中有了空余的空間,操作系統將有兩個選擇來利用這塊空間。一是容納一個新建的進程,二是調入一個以前被掛起的程序。顯然,通常比較傾向於調入一個以前被掛起的進程,給他提供服務,而不是增加系統中的負載總數。
但是這種方案也帶來了一個問題,所有的被掛起的進程在掛起時都處於阻塞態。很明顯,這時如果將一個被阻塞的進程放回內存沒有任何意義。所以我們需要更新之前的模型,新加入兩個狀態:
- 阻塞/掛起態:進程在外存中等待一個事件
- 阻塞/就緒態:進程在外存中,只要被載入內存就可以執行
新的狀態轉換圖:
各個狀態之間的轉換原則暫且不表(: P)。
導致進程掛起的原因
交換:操作系統需要釋放足夠多的內存空間,以調入並執行處於就緒態的進程
其他 OS 原因:操作系統可能掛起後臺進程或工具進程,或者懷疑導致問題的進程
交互式用戶請求:用戶可能希望掛起一個程序的執行,目的是為了調試,檢查並修改程序數據,或者與一個資源的使用進行連接。
定時:一個進程可能周期性的執行,而且可能在等待下一個時間間隔時被掛起
父進程請求:父進程可能會希望掛起後代進程的執行,以檢查或修改掛起的進程,或者協調不同後代進程之間的行為
?
進程描述
操作系統的控制結構
? 操作系統為了管理進程和資源,必須掌握關於每個進程和資源的當前狀態的信息。普遍使用的方法是:操作系統構造並維護他所管理的每個實體的信息表。比如內存表,I/O 表,文件表和進程表。
進程控制結構
進程的位置
? 操作系統在管理和控制進程時,首先必須知道進程的位置,再者,它必須知道在管理時所必須的進程屬性(比如進程ID,進程狀態)。
一個進程的物理表示體現為在內存中的一塊數據,保存著進程的程序(代碼)和數據。此外,程序的執行還涉及到用於跟蹤過程調用和過程間參數傳遞的棧。最後,與每個進程相關聯的還有操作系統用於控制進程的許多屬性。通常,這些屬性的集合稱為進程控制塊。
程序、數據、棧和屬性的集合稱作進程映像。
進程映像中的典型元素:
- 用戶數據:用戶空間中可修改部分,可包括程序數據、用戶棧區域和可修改的程序
- 用戶程序:將被執行的程序
- 系統棧:每個進程有一個或多個後進先出(LIFO)系統棧。棧用於保存參數、過程調用地址和系統調用地址
- 進程控制塊:操作系統控制進程所需要的數據
進程映像的位置依賴於使用的內存管理方案。最簡單的情況就是它位於內存中的一塊連續的空間。考慮其他更為復雜的內存管理方案時進程映像的位置和物理組織將隨之發生變化(比如虛擬內存只載入進程的一部分到內存,分頁使得進程在內存中分布不一定連續等)。
進程屬性
? 復雜的多道程序設計系統需要關於每個進程 的大量信息,如前所述,這些信息可以保存在進程控制塊中。
可以把進程控制信息分成三類:
- 進程標識信息
- 處理器狀態信息
- 進程控制信息
關於處理器狀態信息
? 處理器狀態信息包括處理器寄存器的內容。當一個進程正在運行時,其信息儲存在處理器中,當進程被中斷時,所有的寄存器信息都必須保存起來,使得進程恢復執行時這些信息都可以被恢復。
具體包括:
- 標識符
- 用戶可見寄存器
- 控制和狀態寄存器
- 棧指針
- 調度和狀態信息
- 數據結構
- 等等
關於標識符
? 實際上在所有的操作系統中,對於進程標識符,每個進程都被分配了一個唯一的__數字標識符__。進程標識符可以簡單標識為主進程表中的一個索引(直接映射)。否則,必須有一個映射,使得操作系統可以根據進程標識符定位相應的表(間接映射)。這個標識符在其他地方也很有用,操作系統控制的許多其他表可以使用進程標識符__交叉引用進程表__。
進程控制塊的作用
? 進程控制塊是操作系統中最重要的數據結構。每個進程控制塊包含操作系統所需要的關於進程的__所有信息__。實際上,操作系統中的每個模塊,包括那些涉及調度、資源分配、中斷處理、性能監控和分析的模塊,都可能讀取和修改他們。可以說,資源控制塊集合定義了操作系統的狀態。
這其實也帶來了一個重要的設計問題,我們訪問進程控制塊很容易,但是保護他們不被錯誤的修改確是個難題。具體表現為下面兩個方面。
- 一個例程中有錯誤,可能會破壞進程控制塊,進而破壞了系統對受影響進程的管理能力。
- 進程控制塊的結構或語義的設計變化可能會影響到操作系統中的許多模塊。
進程控制
執行模式
? 在繼續討論操作系統管理進程的方式之前,需要區分通常與操作系統相關聯的以及與用戶程序相關聯的__處理器執行模式__。通常處理器提供至少兩種執行模式——特權態,非特權態。
特權態通常被稱為內核態,而非特權態通常被稱為用戶態。
使用兩種模式的__原因__是,他可以__保護__操作系統和重要的操作系統表(比如進程控制塊)不受用戶程序的幹擾。在內核態下,軟件具有對處理器以及所有指令、寄存器和內存的控制能力,這一級的控制對用戶程序不是必需的,並且安全起見也不是用戶程序可以訪問的。
那麽,處理器是如何知道他正在處於什麽模式下執行以及如何改變這一模式的?
答案是 程序狀態字。程序狀態字(處理器中的一個寄存器)中有一位用於表示執行模式。當程序以用戶態運行時,程序狀態字被設置從而使處理器為用戶態,相應的內核態也是如此。
進程創建
? 之前提過了創建一個進程的事件和與進程相關的數據結構,現在將簡單的描述實際創建進程時包含的步驟。
步驟如下:
- 分配進程標識符 此時,在主進程表中增加一個新表項,表中的每個新表項對應一個進程。
- 給進程分配空間
- 初始化程序控制塊
- 設置正確的連接
- 創建或擴充其他數據結構
進程切換
? 從表面上看,進程切換的功能是很簡單的。在某一時刻,有個正在運行的進程被中斷,操作系統指定另一個進程為運行態,並把控制權交給這個進程。但是這會引發若幹問題。首先,什麽事件觸發進程的切換?其次,模式切換和進程切換之間有什麽的區別?最後,為實現進程的切換,操作系統必須對他控制的各種數據結構做些什麽?
何時切換進程
? 進程切換可以在操作系統從當前正在運行的進程中獲得控制權的任何時刻發生。
首先考慮中斷:
- 時鐘中斷 時間片用盡
- I/O 中斷 進程狀態的切換(考慮五種進程狀態模型)導致的進程切換
- 內存失效 內存失效的進程可能會被設置為阻塞態,操作系統有可能切換另一個程序執行
實際上,大多數操作系統區分兩種類型的系統中斷。一種稱為中斷,另一種稱為__陷阱__。前者與當前正在運行的進程無關的某種類型的外部事件相關。比如 I/O 信號。後者與當前正在運行的進程所產生的錯誤或異常條件相關。
對於陷阱而言,操作系統將根據錯誤的嚴重性決定將進程轉換為退出態,切換其他的進程執行,還是報告一條警告消息繼續執行。
模式切換
中斷階段是指令周期的一部分(即循環的出現)。在中斷階段,處理器檢查是否發生了中斷,這通過中斷信號來表示。如果沒有,處理器繼續取指令周期,即當前進程中的下一條指令。如果存在一條未處理的中斷,處理器需要做以下工作:
- 把程序計數器設置成中斷處理程序的開始地址(開始執行中斷處理程序)
- 從用戶態切換到內核態,使得中斷處理代碼可以包含有特權指令
當中斷發生後,被中斷的進程上下文保存在被中斷的進程控制塊中。環境上下文必須包括稱作處理器狀態信息的進程控制塊部分,這包括程序計數器(執行到了哪條指令)、其他處理器寄存器和棧信息。以實現進程的恢復。
操作系統的執行
基於之前討論過的事實:
- 操作系統與普通的計算機軟件以同樣的方式運行,也即他是由處理器執行的一個程序。
- 操作系統經常釋放控制權,並且依賴與處理器恢復控制權
我們將討論操作系統在計算機中執行的方式。
無進程的內核
這種模式下,操作系統是作為所有的進程之外被執行的。操作系統有自己的內存區和系統棧,用於控制過程調用和返回,處理中斷,進程調度。操作系統是作為一個在特權模式下工作的實體被執行。這種模式一般存在於許多老的操作系統中。
在用戶進程中執行
在較小的機器的操作系統中,常見的方法是在用戶進程的上下文中執行幾乎所有的操作系統軟件。其觀點是操作系統從根本上說是用戶調用的一組例程。在這種模式下,每個進程都包含操作系統,每個進程映像包括內核程序的程序、數據和棧區域(以共享內存的形式)。
基於進程的操作系統
基於進程的操作系統是將操作系統作為一組進程來實現。與其他選擇一樣,作為內核一部分的軟件在內核態下執行。不過在這種情況下,主要的內核函數被組織成獨立的進程,同樣,還可能有一些在任何進程之外的進程切換代碼。
進程描述和控制(os 筆記二)