《操作系統概念》筆記--第三章 進程

進程

進程概念

早期的計算機一次只能執行一個程序。這種程序完全控制系統,並且訪問所有系統資源。相比之下,現在計算機系統允許加載多個程序到內存,以便併發執行。這就導致了進程(peocess)的產生。進程是現在分時系統的工作單元。
程序本身不是進程。程序只是被動(passive)實體,如存儲在磁盤上包含一系列指令的文件(經常稱爲可執行文件(executable file))。
相反,進程是活動(active)實體,具有一個程序計數器用於執行下個執行命令和一組相關資源。

雖然兩個進程可以與同一程序相關聯,但是當做兩個單獨的執行序列。每個都是獨立進程,因爲文本段相同,但是數據,堆及堆棧卻不同。

進程狀態

進程在執行時會改變狀態。共有五種狀態:
新的(new):進程正在創建
運行(running):指令正在執行
等待(waiting):進程等待發生某個事件(如I/O完成或收到信號)
就緒(ready):進程等待分配處理器
終止(terminated):進程已經完成執行

一次只有一個進程在一個處理器上運行(running),但是許多進程可處於就緒(ready)或等待(waiting)狀態。

進程控制塊

操作系統的每個進程表示,採用進程控制塊(Pocess Control Block ,PCB),也叫做任務控制塊(task control block)。
它包含進程相關的七種信息:
進程狀態(process state): 狀態可以包括新的,運行,等待,就緒,終止
程序計數器(program counter):計數器表示程序將要執行的下個指令的地址。
CPU寄存器(CPU register):根據計算機體系結構的不同,寄存器的類型和數量也會不同。它們包括累加器,索引寄存器等等。
CPU調度信息(CPU-scheduling information):這類信息包括進程優先級,調度隊列的指針和其他調度參數。
內存管理信息(memory-management information):這類系統可以包括基地址和界限寄存器的值,頁表或段表等。
記賬信息(accounting information):這類信息包括CPU時間,實際使用時間,時間期限,記賬信息,作業或進程數量等。
I/O狀態信息(I/O state information):這類信息包括分配給進程的I/O設備列表,打開文件列表等。

簡而言之,PCB簡單地作爲這些信息的倉庫,這些信息隨着進程的不同而不同。

進程調度

多道程序設計的目標是,無論何時都有進程運行,從而最大化CPU利用率。
進程調度器(process scheduler)選擇一個可用進程到CPU上執行。
單處理器系統不會具有多個正在運行的進程。如果有多個進程,那麼餘下的需要的等待CPU空閒並能重新調度。

調度隊列

進程在進入系統時,會被加到作業隊列(job queue),這個隊列包括系統內的所有進程。
這個隊列通常用鏈表實現,其頭節點有兩個指針,用於指向鏈表的第一個和最後一個PCB塊;每個PCB還包括一個指針,指向就緒隊列的下一個PCB。
系統還有其他隊列。等待特定I/O設備的進程列表,成爲設備隊列(device queue)。每個設備都有自己的設備隊列。
最初,新進程被加到就緒隊列中,它在就緒隊列中等待,知道被選中執行或被分派。
當該進程分配到CPU並執行時,有以下3種事件可能發生:
進程可能發出I/O請求,並被放到I/O隊列中。
進程可能創建一個新的子進程,並等待其終止。
進程可能由於中斷而被強制釋放CPU,並被放回到就緒隊列中。

前兩種情況,進程最終從等待狀態切換到就緒狀態,並放回到就緒隊列。進程重複這一循環直到終止。然後它就會從所有隊列中刪除,其PCB和資源也被釋放。

調度程序

進程在整個生命週期中,會在各種調度隊列之間遷移。操作系統爲了按一定方式從這些隊列中選擇進程,進程選擇通過適當調度器或調度程序(scheduler)來執行。
長期調度程序(long-term scheduler)從大容量存儲設備(通常爲磁盤)的緩衝池中選擇進程,加到內存中,以便執行。短期調度程序(short-term scheduler)CPU調度程序(CPU scheduler)從準備執行的進程中選擇進程,並分配給CPU。
從上面就很容易看出長期調度程序與短期調度程序的作用與區別。
其中,這兩種調度程序的主要區別是執行效率。
短期調度程序必須經常爲CPU選擇新的進程。進程可能執行幾毫秒,就會等待I//O請求。通常,短期調度程序每100ms至少執行一次。由於執行之間的時間短,短期調度程序必須快速。
而長期調度程序執行並不頻繁,在新進程的創建之前,可能有幾分鐘的間隔。長期調度程序控制多道程序程度(degree of multiprogramming)(內存中的進程數量)。因此,只有在進程離開系統時,才需要長期調度程序的調度。由於每次執行之間的更長時間間隔,長期調度程序可以負擔得起更多時間,以便決定選擇執行那個進程。
重要的是,長期調度程序需要認真選擇。
大多數進程可分爲:I/O爲主或CPU爲主
I/O密集型進程(I/O-bound process),執行I/O比執行計算需要花費更多時間。相反,CPU密集型進程(CPU-bound process)很少產生I/O請求,而是將更多時間用於執行計算。所以,長期調度程序應該選擇I/O密集型和CPU密集型的合理進程組合。

如果所有進程都是I/O密集型的,那麼就緒隊列幾乎總是爲空,從而短期調度程序沒有什麼可做。如果所有進程都是CPU密集型的,那麼I/O等待隊列幾乎總是爲空,從而設備沒有得到使用,因而系統會不平衡。
所以,爲了使得性能最佳,系統需要I/O密集型和CPU密集型的進程組合。
有的操作系統如分時系統,可能引入一個額外的中期調度程序(medium-term scheduler)。
中期調度程序的核心思想是可將進程從內存(或從CPU競爭)中移出,從而降低多道程序程度。之後,進程可被重新調入內存,並從中斷處繼續執行。這種方案稱爲交換(swap)。通過中期調度程序,進程可換出(swap out),並在後來可換入(swap in)。
爲了改善進程組合,或者由於內存需求改變導致過度使用內存從而需要釋放內存,就有必要使用交換

*論述長期調度 ,中期調度,短期調度的差異?

短期調度:短期調度在內存進程中選擇就緒執行的進程加載到CPU
中期調度:中期調度將部分運行進程移出內存,之後又加載進程到內存,從中斷處運行
長期調度:長期調度從大容量存儲設備的緩衝池中選擇進程加載到內存
他們的不同之處是他們執行的頻率。短期調度程序需要經常調用,而長期調用並不頻繁調用,可能在進程離開系統時才被喚起

上下文切換

切換CPU到另一個進程需要保存當前進程狀態和恢復另一個進程的狀態,這個任務稱爲上下文切換(context switch)。
中斷導致CPU從執行當前任務改變到CPU上的進程的上下文,以便在處理後能夠恢復上下文,即先掛起進程,再恢復進程。
進程上下文采用PCB表示,包括CPU寄存器的值,進程狀態和內存信息管理等。
通常,通過執行狀態保存(state save),保存CPU當前狀態(包括內核模式和用戶模式),之後,狀態恢復(state restore)重新開始運行。
*內核採取一些動作以便在兩個進程之間進行上下文切換,請描述一下?

操作系統保存正在運行的進程中的上下文,然後恢復將要運行進程的上下文

進程運行

大多數系統的進程能夠併發執行,它們可以動態創建和刪除。

進程創建

進程在執行過程中可能創建多個新的進程。創建進程稱爲父進程,而新的進程稱爲子進程。每個新進程可以在創建其他的進程,從而形成進程樹(process tree)。
大多數的操作系統對進程的識別採用的是唯一的進程標識符(process identifier, pid),這通常是一個整數值。

系統內的每個進程都有唯一的pid,它可以用作索引,以便訪問內核中的進程的各種屬性。

一般來說,當一個進程創建子進程時,該子進程會需要一定的資源(CPU時間,內存等)來完成任務,有兩種資源獲得來源:
子進程可以從操作系統那裏直接獲得資源
也可以父進程那裏獲得資源子集。
除了提供各種物理和邏輯資源外,父進程也可能向子進程傳遞初始化數據(或輸入)。
當進程創建新進程時,可有兩種執行可能:
父進程與子進程併發執行
父進程等待,直到某個或全部子進程執行完
新進程的地址空間也有兩種可能:
子進程是父進程的複製品
子進程加載另一個程序(如使用系統調用exec())

進程終止

當進程完成執行最後語句並且通過系統調用exit()請求操作系統刪除自身時,進程終止。
父進程終止子進程的原因有很多,如以下三種
子進程使用了超過它所分配的資源(爲判定是否發生這種情況,父進程應有一個機制,以檢查子進程的狀態)。
分配給子進程的任務,不再需要。
父進程正在退出,而且操作系統不允許無父進程的子進程繼續執行。
級聯終止
有些系統不允許子進程在父進程已終止的情況下存在。對於這類系統,如果一個進程終止,那麼它的所有子進程也應終止。這種現象,就叫做級聯終止。
當一個進程終止時,操作系統會釋放其資源。

不過,它位於進程表中的條目還是在的,直到它的父進程調用wait(),這是因爲進程表包含了進程的退出狀態。
當進程已經終止,但是其父進程尚未調用wait(),這樣的進程稱爲殭屍進程(zonbie process)。
所有進程終止時都會過度到這種狀態,但是一般殭屍只是短暫存在。一旦父進程調用了wait(),殭屍進程的進程標識符和它在進程表中的條目就會釋放。
如果父進程沒有調用wait()就終止,子進程就會稱爲孤兒進程(orphan process)。

進程間通信

操作系統內的併發執行進程可以是獨立的也可以是協作的。
如果一個進程不能影響其它進程或受其他進程影響,那麼該進程是獨立的。

顯然,不與任何其他進程共享數據的進程是獨立的。

如果一個進程能影響其他進程或受其他進程所影響,那麼該進程是協作的。

顯然,與其他進程共享數據的進程爲協作進程

提供環境允許進程協作,有很多理由與好處,如以下四種
信息共享(information sharing):由於多個用戶可能對同樣的信息感興趣(例如共享文件),所以應提供環境以允許併發訪問這些信息。
計算加速(computation speedup):可以把一個任務分成多個子任務,每個子任務可以與其他子任務併發執行。
模塊化(modulrity):可能需要按模塊化方式構造系統,可將系統功能分成獨立的進程或線程。
方便(convenience):即使單個用戶也可能同時執行許多任務。
進程間通信(InterProcess Communication, IPC)機制 **
協作進程需要有一種
進程間通信(InterProcess Communication,IPC)機制,以允許進程相互交換數據與信息。
進程間通信有
兩種**基本模型:
共享內存(shared memory)
消息傳遞(message passing)

共享內存會建立一塊供協作進程共享的內存區域,進程通過向此共享區域讀出與寫入數據來交換信息
消息傳遞模型通過在協作進程間交換消息來實現通信

兩者的比較:
消息傳遞對於交換較少數量的數據很有用,因爲無需避免衝突。對於分佈式系統,消息傳遞也比共享內存更易實現。
共享內存可以快於消息傳遞。這是因爲消息傳遞實現經常採用系統調用,因此需要消耗更多時間以便內核介入。與此相反,共享內存系統僅在建立共享區域時需要調用系統調用,一旦建立共享內存,所有訪問都可以作爲常規內存訪問,無需藉助內核。

共享內存系統

採用共享內存的進程間通信,需要通信進程建立共享內存區域。
生產者-消費者問題
**生產者(producer)進程生產信息,以供消費者(consumer)**進程消費
解決生產者消費者的問題的方法之一是,採用共享內存。爲了允許生產者進程和消費者進程併發執行,應有一個可用的緩衝區,以被生產者填充和被消費者清空。這個緩衝區駐留在生產者進程和消費者進程的共享區域內。當消費者使用一項時,生產者可產生另一項。

生產者和消費者必須同步,這樣消費者和不會試圖消費一個尚未生產出來的項。

緩衝區類型分爲兩種
無界緩衝區(unbounded-buffer):沒有限制緩衝區的大小。

消費者不得不等待新的項,但生產者總是可以產生新項。

有界緩衝區(bounded-buffer):固定大小的緩衝區。

對於這種情況,如果緩衝區爲空,那麼消費者必須等待。如果緩衝區已滿,那麼生產者必須等待。

消息傳遞系統

操作系統提供機制,以便協作進程通過消息傳遞功能進行通信。
這有三種方法,用於實現鏈路和操作send()/receive():
直接或間接的通信
同步或異步的通信
自動或顯式的緩衝

命名

直接通信(direct communication)
直接通信需要通信的每個進程必須明確指定通信的接收者或發送者。

send(p,message): 向進程P發送message
receive(Q,message):從進程Q接收message

這種方案具有以下三種屬性:
在需要通信的每對進程之間,自動建立鏈路。進程僅需知道對方身份就可進行交流。
每個鏈路只與兩個進程相關
每對進程之間只有一個鏈路

這種方案展示了尋址的對稱性(symmetry),即發送和接收進程必須指定對方,以便通信。

下面一種採用尋址的非對稱性(asymmetry),即只要發送者指定接收者,而接收者不需要指定發送者。

send(P,message):向進程P發送message
receive(id,message):從任何進程,接受message,這裏變量id被設置成與其通信進程的名稱。

這兩個方案都有一定的缺點:生成進程定義的有限模塊化。
更改進程標識符可能需要分析所有其他進程定義,所有舊的標識符的引用都應被找到,以便修改成爲新標識符。
間接通信(indirect communication)
間接通信通過郵箱或端口來發送和接收消息。

郵箱可以抽象成一個對象,進程可以向其中存放消息,也可從中刪除消息,每個郵箱都有一個唯一的標識符。

一個進程可以通過多個不同郵箱與另一個進程通信

send(A, message):向郵箱A發送message
receive(A, message):從郵箱A接受message

這種方案有以下三種特點:
只有在兩個進程共享一個郵箱時,才能建立通信線路。
一個鏈路可以與兩個甚至更多進程相關聯。
兩個通信進程之間可有多個不同鏈路,每個鏈路對應於一個郵箱
下面舉一個問題:
假設進程P1,P2和P3都共享郵箱A,進程P1發送一個消息到A,而進程P2和P3都對A執行receive()。那麼哪個進程會收到P1發送的消息?
答案不是唯一的,取決於所選擇的方案:
允許一個鏈路最多與兩個進程關聯
允許一次最多一個進程執行receive()
允許系統隨意選擇一個進程以便接收消息(即P2和P3兩者之一都可以接收消息,但不能兩個都可以)

系統同樣可以定義一個算法選擇哪個進程是接收者,系統還可以讓發送者指定接收者

郵箱可以爲進程或操作系統擁有
如果郵箱爲進程所擁有(即郵箱是進程地址空間的一部分),那麼需要區分所有者和使用者。當擁有郵箱的進程終止,那麼郵箱就會消失。任何進程後來向該郵箱發送消息,都會得知郵箱不存在。
如果郵箱爲操作系統擁有,那麼郵箱是獨立的,他不屬於某個特定進程。

同步

消息傳遞可以是阻塞(blocking)非阻塞(nonblocking),也稱爲同步(synchronous)異步(asynchronous)
發送接收有以下四種
阻塞發送(blocking send):發送進程阻塞,直到消息由接收進程或郵箱所接收
非阻塞發送(nonblocking send):發送進程發送消息,並且恢復操作,不會等待
阻塞接收(blocking receive):接收進程阻塞,直到有消息可用
非阻塞接收(nonblocking receive):接收進程收到一個有效消息或空消息

不同組合的send()和receive()都有可能

緩存

不管通信是直接的還是間接的,通信交換的消息總是駐留在臨時隊列中。也就是緩存
隊列實現有三種方法:
零容量(zero capacity):隊列的最大長度爲0,因此,鏈路中不能有任何消息處於等待,這種情況下,發送者應該阻塞,直到接收者接收到消息。
有限容量(bounded capacity):隊列長度爲有限的n,因此最多隻能有n個消息駐留其中,如果在發送新消息時隊列未滿,那麼該消息可放在隊列中,且發送者可以繼續執行而不必等待。然而,鏈路容量有限,如果鏈路已滿,那麼發送者應該阻塞,知道隊列空間有可用的爲止。
無限容量(unbounded capacity):隊列長度可以無限。因此,不管多少消息都可在其中等待。發送者從不阻塞。

總結與梳理

進程的概念和五種狀態
PCB的概念與包含進程的七種信息
進程調度與三種調度程序
進程創建到結束的過程

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