什么是進(jìn)程
在給進(jìn)程下定義前,先考慮以下幾個(gè)概念:
- 一個(gè)計(jì)算機(jī)平臺(tái)包括一組硬件資源:比如處理器、內(nèi)存、I/O 模塊、定時(shí)器和磁盤驅(qū)動(dòng)器等。
- 計(jì)算機(jī)程序是為執(zhí)行某些任務(wù)而開發(fā)的。典型情況下,它們接受外來的輸入,做一些處理后,輸出結(jié)果。
- 直接根據(jù)給定的硬件平臺(tái)寫應(yīng)用程序效率是低下的
- 開發(fā)操作系統(tǒng)是為了給應(yīng)用程序提供一個(gè)方便、安全和一直的接口。操作系統(tǒng)是計(jì)算機(jī)硬件和應(yīng)用程序直接的一層軟件,對(duì)應(yīng)用程序和工具提供了支持。
- 可以把操作系統(tǒng)想象為資源的統(tǒng)一抽象表示,可以被應(yīng)用程序請(qǐng)求和訪問。資源包括內(nèi)存、網(wǎng)絡(luò)接口和文件系統(tǒng)等。
有了上述概念,現(xiàn)在就可以討論操作系統(tǒng)怎樣以一個(gè)有序的方式管理應(yīng)用程序的執(zhí)行,以達(dá)到以下目的:
- 資源對(duì)多個(gè)應(yīng)用程序是可用的
- 物理處理器在多個(gè)應(yīng)用程序間切換以保證所有程序都在執(zhí)行中
- 處理器和 I/O 設(shè)備能得到充分的利用
現(xiàn)代操作系統(tǒng)采用的方法都是依據(jù)對(duì)應(yīng)于一個(gè)或多個(gè)進(jìn)程存在的應(yīng)用程序執(zhí)行的一種模型。
關(guān)于進(jìn)程有很多定義:
- 一個(gè)正在執(zhí)行的程序
- 計(jì)算機(jī)中正在運(yùn)行的程序的一個(gè)實(shí)例
- 可以分配給處理器并由處理器執(zhí)行的一個(gè)實(shí)體
- 由單一的順序的執(zhí)行線程、一個(gè)當(dāng)前狀態(tài)和一組相關(guān)的系統(tǒng)資源所描述的活動(dòng)單元
進(jìn)程狀態(tài)
一個(gè)被執(zhí)行的程序,操作系統(tǒng)會(huì)為該程序創(chuàng)建一個(gè)進(jìn)程或任務(wù),并且控制進(jìn)程的執(zhí)行。
簡(jiǎn)單來說,程序只有兩種狀態(tài):運(yùn)行態(tài)、未運(yùn)行態(tài)。
兩狀態(tài)進(jìn)程模型
- 當(dāng)操作系統(tǒng)創(chuàng)建一個(gè)新進(jìn)程時(shí),它將該進(jìn)程以未運(yùn)行態(tài)加入到系統(tǒng)中,操作系統(tǒng)知道進(jìn)程的存在,并等待執(zhí)行機(jī)會(huì)。
- 當(dāng)前運(yùn)行的進(jìn)程不時(shí)中斷,操作系統(tǒng)的分派器將選擇一個(gè)新進(jìn)程運(yùn)行。
- 前一個(gè)進(jìn)程從運(yùn)行態(tài)轉(zhuǎn)換到未運(yùn)行態(tài),另一個(gè)從未運(yùn)行態(tài)轉(zhuǎn)換到運(yùn)行態(tài)。
同時(shí),未運(yùn)行的進(jìn)程需保持在某種類型的隊(duì)列中,并等待它們的執(zhí)行時(shí)機(jī)。
上圖中的排隊(duì)圖可以描述分派器的行為:被中斷的進(jìn)程轉(zhuǎn)移到等待進(jìn)程隊(duì)列中,或者,如果進(jìn)程以及結(jié)束或取消,則被銷毀。在任何一種情況下,分派器均從隊(duì)列中選擇一個(gè)進(jìn)程來執(zhí)行。
通過這個(gè)模型,可以看出操作系統(tǒng)需要用某種方式來表示每個(gè)進(jìn)程,使得操作系統(tǒng)能夠跟蹤它,也就是說需要有一些與進(jìn)程相關(guān)的信息,包括進(jìn)程在內(nèi)存中的狀態(tài)和位置,即進(jìn)程控制塊。
進(jìn)程控制塊
進(jìn)程在任意時(shí)間都可以唯一地被表征為以下元素:
簡(jiǎn)化的進(jìn)程控制塊
- 標(biāo)識(shí)符:存儲(chǔ)在進(jìn)程控制塊中的數(shù)字標(biāo)識(shí)符,包括(次進(jìn)程的標(biāo)識(shí)符-進(jìn)程 ID,父進(jìn)程標(biāo)識(shí)符,用戶標(biāo)識(shí)符-用戶 ID)
- 狀態(tài):進(jìn)程狀態(tài)(如運(yùn)行態(tài),就緒態(tài),等待態(tài)等)
- 優(yōu)先級(jí):用于描述進(jìn)程調(diào)度優(yōu)先級(jí)的一個(gè)或多個(gè)域。
- 程序計(jì)數(shù)器:程序中即將被執(zhí)行的下一條指令的地址
- 內(nèi)存指針:包括程序代碼和進(jìn)程相關(guān)數(shù)據(jù)的指針,還有和其他進(jìn)程共享內(nèi)存塊的指針
- 上下文數(shù)據(jù):進(jìn)程執(zhí)行時(shí)處理器的寄存器的數(shù)據(jù)
- I/O 狀態(tài)信息:包括顯示的 I/O 請(qǐng)求、分配給進(jìn)程的 I/O 設(shè)備和被進(jìn)程使用的文件列表等
- 記賬信息:可能包括處理器時(shí)間總和、使用的時(shí)鐘數(shù)總和、時(shí)間限制、記賬號(hào)等。
這些信息被存放在一個(gè)叫進(jìn)程控制塊的數(shù)據(jù)結(jié)構(gòu)中,它由操作系統(tǒng)創(chuàng)建和管理。進(jìn)程控制塊是進(jìn)程存在的唯一標(biāo)志,也就是說任何一個(gè)進(jìn)程只要進(jìn)程創(chuàng)建了它就一定有一個(gè)跟它相對(duì)應(yīng)的進(jìn)程控制塊,進(jìn)程結(jié)束了進(jìn)程控制塊就會(huì)被操作系統(tǒng)回收,進(jìn)程在執(zhí)行的過程對(duì)進(jìn)程的所有操作都是通過進(jìn)程控制塊來實(shí)現(xiàn)的。
進(jìn)程創(chuàng)建和終止
進(jìn)程除運(yùn)行和未運(yùn)行外,在進(jìn)程的生命周期中,創(chuàng)建和終止都是不可避免的。
進(jìn)程創(chuàng)建
通常有4個(gè)事件會(huì)導(dǎo)致創(chuàng)建一個(gè)進(jìn)程:
- 新的批量作業(yè)
- 交互登錄。終端用戶登錄到系統(tǒng)
- 操作系統(tǒng)因?yàn)樘峁┮豁?xiàng)服務(wù)而創(chuàng)建。操作系統(tǒng)可以創(chuàng)建一個(gè)進(jìn)程,代表用戶程序執(zhí)行一個(gè)功能,使用戶無需等待。
- 由現(xiàn)有進(jìn)程派生?;谀K化的考慮,或者為了開發(fā)并行性,用戶程序可以指示創(chuàng)建多個(gè)進(jìn)程。
當(dāng)一個(gè)進(jìn)程派生另一個(gè)進(jìn)程時(shí),前一個(gè)稱為父進(jìn)程,被派生的被稱為子進(jìn)程。
一旦操作系統(tǒng)決定創(chuàng)建一個(gè)新進(jìn)程,它就會(huì)按以下步驟進(jìn)行:
- 給新進(jìn)程分配一個(gè)唯一的進(jìn)程標(biāo)識(shí)符。
- 給進(jìn)程分配空間。
- 初始化進(jìn)程控制塊。
- 設(shè)置正確的連接。(例如,如果操作系統(tǒng)把每個(gè)調(diào)度隊(duì)列都保存成鏈表,則新進(jìn)程必須放置在就緒或就緒/掛起鏈表中)。
- 創(chuàng)建或擴(kuò)充其他數(shù)據(jù)結(jié)構(gòu)。
進(jìn)程終止
有很多事件可以導(dǎo)致進(jìn)程終止,比如:
- 進(jìn)程完成
- 進(jìn)程超時(shí)。進(jìn)程運(yùn)行時(shí)間超過規(guī)定的時(shí)限
- 無可用內(nèi)存
- I/O 失敗
- 算術(shù)錯(cuò)誤
- 無效指令
- 父進(jìn)程終止
- 父進(jìn)程請(qǐng)求
- 。。。
五狀態(tài)模型
系統(tǒng)中還存在著一些處于非運(yùn)行狀態(tài)但已經(jīng)就緒等待執(zhí)行的進(jìn)程,而且還存在另一些處于阻塞狀態(tài)等待 I/O 操作結(jié)束的進(jìn)程。
這時(shí),就緒態(tài)(ready)和阻塞態(tài)(blocked)出現(xiàn)了,兩狀態(tài)模型升級(jí)為了5狀態(tài)模型,5個(gè)狀態(tài)如下:
五狀態(tài)進(jìn)程模型
- 運(yùn)行態(tài):該進(jìn)程正在執(zhí)行
- 就緒態(tài):進(jìn)程做好了準(zhǔn)備,等待處理器調(diào)度
- 阻塞/等待態(tài):進(jìn)程在某些事件發(fā)生前不能執(zhí)行,比如 I/O 操作完成
- 新建態(tài):剛剛創(chuàng)建的進(jìn)程,操作系統(tǒng)還沒有把它加入到可執(zhí)行進(jìn)程組中。通常是進(jìn)程控制塊已經(jīng)創(chuàng)建但還沒有被加載到內(nèi)存中。
- 退出態(tài):操作系統(tǒng)從可執(zhí)行進(jìn)程組中釋放出的進(jìn)程,或者是因?yàn)樗陨硗V沽耍蛘呤且驗(yàn)槟撤N原因被取消。
新建-就緒: 操作系統(tǒng)準(zhǔn)備好再接納一個(gè)進(jìn)程時(shí),把一個(gè)進(jìn)程從新建態(tài)轉(zhuǎn)換到就緒態(tài)。大多數(shù)系統(tǒng)基于心有的進(jìn)程數(shù)或分配給現(xiàn)有進(jìn)程的虛擬內(nèi)存數(shù)量設(shè)置一些限制,以確保不會(huì)因?yàn)榛钴S進(jìn)程數(shù)量過多而導(dǎo)致系統(tǒng)的性能下降。
就緒-退出: 在某些系統(tǒng)中,父進(jìn)程可以在任何時(shí)候終止一個(gè)子進(jìn)程。如果一個(gè)父進(jìn)程終止,與該父進(jìn)程相關(guān)的所有子進(jìn)程都將被終止。
掛起
就緒態(tài)、運(yùn)行態(tài)和阻塞態(tài)提供了一種為進(jìn)程行為建立模型的系統(tǒng)方法,但有個(gè)問題需要考慮:每個(gè)被執(zhí)行的進(jìn)程必須完全載入內(nèi)存,當(dāng)一個(gè)進(jìn)程在等待 I/O 操作時(shí),處理器可以轉(zhuǎn)移到另一個(gè)進(jìn)程,但 I/O 活動(dòng)比CPU 計(jì)算速度慢很多,因此大多數(shù)情況下處理器在多數(shù)時(shí)候都是空閑的。但是如果內(nèi)存中都是阻塞態(tài)的進(jìn)程怎么辦呢?
- 一種辦法就是擴(kuò)充內(nèi)存已適應(yīng)更多的進(jìn)程
- 另一種方案是把進(jìn)程中的某個(gè)內(nèi)存的一部分或者全部移到磁盤中。當(dāng)內(nèi)存中沒有處于就緒態(tài)的進(jìn)程時(shí),操作系統(tǒng)就把被阻塞的進(jìn)程換出到磁盤中的掛起隊(duì)列,這是暫時(shí)保存從內(nèi)存中被驅(qū)逐出的進(jìn)程隊(duì)列,或者說是被掛起的進(jìn)程隊(duì)列。操作系統(tǒng)在此之后取出掛起隊(duì)列中的另一個(gè)進(jìn)程,或者接受一個(gè)新進(jìn)程的請(qǐng)求,將其納入內(nèi)存運(yùn)行。
有掛起態(tài)的進(jìn)程狀態(tài)轉(zhuǎn)換圖
這里有兩個(gè)獨(dú)立的概念:進(jìn)程是否在等待一個(gè)事件(阻塞與否)以及進(jìn)程是否已經(jīng)被換出內(nèi)存(掛起與否)。這里需要4個(gè)狀態(tài):
- 就緒態(tài):進(jìn)程在內(nèi)存中并可以執(zhí)行
- 阻塞態(tài):進(jìn)程在內(nèi)存中并等待一個(gè)事件
- 阻塞/掛起態(tài):進(jìn)程在外存中并等待一個(gè)事件
- 就緒/掛起態(tài):進(jìn)程在外存中,但是只要被載入內(nèi)存就可以執(zhí)行
現(xiàn)在狀態(tài)轉(zhuǎn)換如下:
阻塞-阻塞/掛起:如果沒有就緒進(jìn)程,則至少一個(gè)阻塞進(jìn)程被換出,為另一個(gè)沒有阻塞的進(jìn)程讓出空間
阻塞/掛起-就緒/掛起:如果等待事件發(fā)生了,比如 I/O 不再阻塞,則處于阻塞/掛起 狀態(tài)的進(jìn)程可以轉(zhuǎn)換到 就緒/掛起狀態(tài)。
阻塞/掛起-阻塞:比如一個(gè)進(jìn)程終止了,釋放了一些內(nèi)存空間,阻塞/掛起隊(duì)列中有一個(gè)進(jìn)程比 就緒/掛起隊(duì)列中的任何任何進(jìn)程的優(yōu)先級(jí)都要高,并且操作系統(tǒng)有理由相信阻塞進(jìn)程的時(shí)間很快就會(huì)發(fā)生,這時(shí),把阻塞進(jìn)程而不是就緒進(jìn)程調(diào)入內(nèi)存是合理的。
進(jìn)程控制
大多數(shù)處理器至少支持兩種執(zhí)行模式,某些指令只能在特權(quán)態(tài)下運(yùn)行,包括讀取或改變諸如程序狀態(tài)之類控制寄存器的指令,原始 I/O 指令和與內(nèi)存管理相關(guān)的指令。另外有部分內(nèi)存區(qū)域僅在特權(quán)態(tài)下可以被訪問到。
特權(quán)態(tài):特權(quán)態(tài)可稱做系統(tǒng)態(tài)、控制態(tài)或內(nèi)核態(tài),內(nèi)核態(tài)指的是操作系統(tǒng)的內(nèi)核。
用戶態(tài):用戶程序常在該模式下運(yùn)行
兩種模式可以保護(hù)操作系統(tǒng)和重要的操作系統(tǒng)表不受用戶程序的干涉。
操作系統(tǒng)內(nèi)核的典型功能:
操作系統(tǒng)內(nèi)核的典型功能
進(jìn)程切換
從表面看,進(jìn)程切換非常簡(jiǎn)單。在某一時(shí)刻,操作系統(tǒng)中斷正在運(yùn)行的進(jìn)程,然后指定另一個(gè)進(jìn)程為運(yùn)行態(tài),并把控制權(quán)交給這個(gè)進(jìn)程。但是現(xiàn)在會(huì)有幾個(gè)問題:
- 什么事件觸發(fā)進(jìn)程切換
- 模式切換和進(jìn)程切換的區(qū)別
- 進(jìn)程切換時(shí),操作系統(tǒng)要做哪些工作
何時(shí)切換進(jìn)程?
進(jìn)程切換可以在操作系統(tǒng)從當(dāng)前正在運(yùn)行的進(jìn)程中獲得控制權(quán)的任何時(shí)刻發(fā)生。以下是可能把控制權(quán)交給操作系統(tǒng)的事件:
進(jìn)程執(zhí)行的中斷機(jī)制
系統(tǒng)中斷通常分為兩種,一種是中斷,另一種是陷阱。
中斷與當(dāng)前正在運(yùn)行的進(jìn)程無關(guān)的某種類型的外部事件相關(guān),比如 I/O 操作;陷阱與當(dāng)前正在運(yùn)行的進(jìn)程鎖產(chǎn)生的錯(cuò)誤或異常條件相關(guān),比如非法的文件訪問。
以下是一些常見的中斷事件:
- 時(shí)鐘中斷:操作系統(tǒng)確認(rèn)當(dāng)前正在運(yùn)行的進(jìn)程的執(zhí)行時(shí)間已經(jīng)超過了最大允許時(shí)間段(時(shí)間片:即進(jìn)程在被中斷前可以執(zhí)行的最大時(shí)間段),進(jìn)程必須切換到就緒態(tài),調(diào)入另一個(gè)進(jìn)程。
- I/O 中斷:進(jìn)程等待 I/O 活動(dòng)。
- 內(nèi)存失效:處理器訪問一個(gè)虛擬內(nèi)存地址,且次地址單元不在內(nèi)存中,操作系統(tǒng)必須從外存中把包含這個(gè)引用的內(nèi)存塊調(diào)入內(nèi)存中。在發(fā)出調(diào)入內(nèi)存塊的 I/O 請(qǐng)求之后,操作系統(tǒng)可能會(huì)執(zhí)行一個(gè)進(jìn)程切換,以恢復(fù)另一個(gè)進(jìn)程的執(zhí)行,發(fā)生內(nèi)存失效的進(jìn)程被置為阻塞態(tài),當(dāng)前的塊調(diào)入內(nèi)存中時(shí),該進(jìn)程被置為就緒態(tài)。
對(duì)于陷阱,操作系統(tǒng)首先確認(rèn)錯(cuò)誤或者異常是否是致命的。如果是,當(dāng)前進(jìn)程被轉(zhuǎn)換到退出態(tài);如果不是,操作系統(tǒng)的動(dòng)作取決于錯(cuò)誤的種類和操作系統(tǒng)的設(shè)計(jì)(有可能是視圖恢復(fù)或通知用戶)。
操作系統(tǒng)也可能被來自正在執(zhí)行的程序的系統(tǒng)調(diào)用激活,比如打開文件,通常,使用系統(tǒng)調(diào)用會(huì)導(dǎo)致把當(dāng)前進(jìn)程置為阻塞態(tài)
系統(tǒng)調(diào)用
Unix 系統(tǒng)是由用戶空間(userland)和內(nèi)核組成。Unix 內(nèi)核位于計(jì)算機(jī)硬件之上,是與搖籃嗎交互的中介。這些交互包括通過問卷系統(tǒng)進(jìn)程讀/寫、在網(wǎng)絡(luò)上發(fā)送數(shù)據(jù)、分配內(nèi)存,以及通過揚(yáng)聲器播放音頻。這些都是用戶應(yīng)用程序所不能涉及的,只能通過系統(tǒng)調(diào)用來完成。
系統(tǒng)調(diào)用為內(nèi)核和用戶空間搭建了橋梁。規(guī)定了程序和計(jì)算機(jī)硬件直接所允許發(fā)生的一切交互。
模式切換和進(jìn)程切換是不同的。發(fā)生模式切換可以不改變正處于運(yùn)行態(tài)的進(jìn)程的狀態(tài),而進(jìn)程被轉(zhuǎn)換到另一個(gè)狀態(tài)操作系統(tǒng)必須使其環(huán)境產(chǎn)生實(shí)質(zhì)性的變化。
進(jìn)程切換步驟如下:
- 保存處理器上下文環(huán)境,包括程序計(jì)數(shù)器和其他寄存器
- 更新當(dāng)前處于運(yùn)行態(tài)進(jìn)程的進(jìn)程控制塊
- 將進(jìn)程的進(jìn)程控制塊移到相應(yīng)的隊(duì)列(就緒、掛起等)
- 選擇另一個(gè)進(jìn)程執(zhí)行
- 更新所選擇進(jìn)程的進(jìn)程控制塊,包括將進(jìn)程的狀態(tài)變?yōu)檫\(yùn)行態(tài)
- 更新內(nèi)存管理的數(shù)據(jù)結(jié)構(gòu)
- 恢復(fù)處理器在被選擇的進(jìn)程最近一次切換出運(yùn)行態(tài)時(shí)的上下文環(huán)境。
下一篇將介紹 Unix 進(jìn)程
參考
- 《操作系統(tǒng)-精髓與設(shè)計(jì)原理》