第二章 進(jìn)程的描述與控制
前趨圖和程序執(zhí)行
程序的順序執(zhí)行
單道程序設(shè)計(jì) -> 程序的順序執(zhí)行
在程序順序執(zhí)行時(shí)庭惜,具有這樣三個(gè)特征:
- 順序性:處理機(jī)嚴(yán)格按照程序所規(guī)定的順序執(zhí)行丰泊,即每一操作必須在下一操作開始之前結(jié)束赦邻;
- 封閉性:程序在封閉的環(huán)境下運(yùn)行,獨(dú)占全機(jī)資源囚霸,資源的狀態(tài)(除初始狀態(tài)外)只有本程序才能改變瞧省,程序一旦開始執(zhí)行其結(jié)果就不受外界影響;
- 可再現(xiàn)性:只要程序執(zhí)行時(shí)的環(huán)境和初始條件相同累澡,程序重復(fù)執(zhí)行時(shí)就可以獲得相同的結(jié)果梦抢。
程序的并發(fā)執(zhí)行
多道程序設(shè)計(jì) -> 程序的并發(fā)執(zhí)行
程序并發(fā)執(zhí)行時(shí)雖然提高了系統(tǒng)的吞吐量和資源利用率,但由于它們共享系統(tǒng)資源愧哟,以及它們?yōu)橥瓿梢豁?xiàng)任務(wù)而相互合作奥吩,致使這些并發(fā)執(zhí)行的程序之間形成互相制約的關(guān)系,給程序的并發(fā)執(zhí)行帶來新特征:
- 間斷性:程序在并發(fā)執(zhí)行時(shí)由于共享系統(tǒng)資源以及為完成同一項(xiàng)任務(wù)而相互合作蕊梧,致使這些程序之間形成了相互制約的關(guān)系霞赫,相互制約導(dǎo)致并發(fā)程序具有“執(zhí)行——暫停——執(zhí)行”這種間斷性的活動(dòng)規(guī)律肥矢;
- 失去封閉性:當(dāng)系統(tǒng)中存在多個(gè)并發(fā)執(zhí)行的程序時(shí)端衰,系統(tǒng)中的各種資源將為它們所共享,這些資源的狀態(tài)也由這些程序來改變甘改,致使其中任一程序在運(yùn)行時(shí)其環(huán)境都會(huì)受到其它程序的影響旅东;
- 不可再現(xiàn)性:程序在并發(fā)執(zhí)行時(shí)由于失去了封閉性,其計(jì)算結(jié)果必將與并發(fā)程序的執(zhí)行速度有關(guān)十艾,也將導(dǎo)致其又失去可再現(xiàn)性抵代。
進(jìn)程的描述
進(jìn)程的定義和特征
進(jìn)程的定義
PCB:為了使參與并發(fā)執(zhí)行的每個(gè)程序(含數(shù)據(jù))都能獨(dú)立運(yùn)行,在操作系統(tǒng)中必須為之配置一個(gè)專門的數(shù)據(jù)結(jié)構(gòu)疟羹,稱為進(jìn)程控制塊(Process Control Block主守,PCB)禀倔。系統(tǒng)利用PCB來描述進(jìn)程的基本情況和活動(dòng)過程,進(jìn)而管理和控制進(jìn)程参淫。
注意:PCB是進(jìn)程存在的唯一定義救湖。
進(jìn)程實(shí)體:又稱進(jìn)程映像,由程序段涎才、相關(guān)數(shù)據(jù)段和PCB三部分構(gòu)成鞋既,一般情況下把進(jìn)程實(shí)體簡稱為進(jìn)程链沼。
進(jìn)程的定義:進(jìn)程是進(jìn)程實(shí)體的運(yùn)行過程茅诱,是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位。
注意:嚴(yán)格來說進(jìn)程實(shí)體和進(jìn)程不同:進(jìn)程實(shí)體是靜態(tài)的昼蛀,進(jìn)程是動(dòng)態(tài)的棕兼。如果不專門考察兩者的區(qū)別就可以認(rèn)為“進(jìn)程實(shí)體就是進(jìn)程”陡舅,也可以說:進(jìn)程由程序段、數(shù)據(jù)段伴挚、PCB三部分組成靶衍。
進(jìn)程的特征
- 結(jié)構(gòu)性:每個(gè)進(jìn)程都會(huì)配置一個(gè)PCB,進(jìn)程具有程序所沒有的PCB結(jié)構(gòu)茎芋,進(jìn)程由程序段颅眶、數(shù)據(jù)段、PCB三部分組成田弥;
- 動(dòng)態(tài)性:進(jìn)程的實(shí)質(zhì)是進(jìn)程實(shí)體的執(zhí)行過程涛酗,動(dòng)態(tài)性是進(jìn)程最基本的特征;
- 并發(fā)性:多個(gè)進(jìn)程實(shí)體同時(shí)存在于內(nèi)存中偷厦,且能在一段時(shí)間內(nèi)同時(shí)運(yùn)行商叹;
- 獨(dú)立性:進(jìn)程實(shí)體是一個(gè)能獨(dú)立運(yùn)行、獨(dú)立獲得資源和獨(dú)立接受調(diào)度的基本單位只泼;
- 異步性:進(jìn)程是按異步方式運(yùn)行的沈自,即按各自獨(dú)立的、不可預(yù)知的速度向前推進(jìn)辜妓。
進(jìn)程的基本狀態(tài)及其轉(zhuǎn)換
進(jìn)程的三種基本狀態(tài)
- 就緒:進(jìn)程已分配到除CPU以外的所有必要資源枯途,只要再獲得CPU便可立即執(zhí)行;
- 執(zhí)行:進(jìn)程已經(jīng)獲得CPU籍滴,其程序正在執(zhí)行酪夷;
- 阻塞:正在執(zhí)行的進(jìn)程由于發(fā)生某事件(如I/O請求、申請緩沖區(qū)失敗等)暫時(shí)無法繼續(xù)執(zhí)行孽惰。
創(chuàng)建狀態(tài)和終止?fàn)顟B(tài)
- 創(chuàng)建狀態(tài):進(jìn)程正在被創(chuàng)建晚岭,操作系統(tǒng)為進(jìn)程分配資源、初始化PCB勋功;
- 終止?fàn)顟B(tài):進(jìn)程正在被撤銷坦报,操作系統(tǒng)會(huì)回收進(jìn)程擁有的資源库说,撤銷PCB。
基本狀態(tài)的轉(zhuǎn)換
掛起操作和進(jìn)程狀態(tài)的轉(zhuǎn)換
掛起操作的引入
- 終端用戶的需要:便于用戶研究自己的程序的執(zhí)行情況或?qū)Τ绦蜻M(jìn)行修改片择;
- 父進(jìn)程請求:父進(jìn)程希望暫停子進(jìn)程潜的,以便考察和修改該子進(jìn)程或協(xié)調(diào)各子進(jìn)程之間的活動(dòng);
- 負(fù)荷調(diào)節(jié)的需要:當(dāng)實(shí)時(shí)系統(tǒng)中的工作負(fù)荷較重時(shí)可以把一些不重要的進(jìn)程掛起字管,以保證系統(tǒng)的正常運(yùn)行啰挪;
- 操作系統(tǒng)的需要:便于操作系統(tǒng)檢查運(yùn)行中的資源使用情況或進(jìn)行記賬。
引入掛起操作后進(jìn)程狀態(tài)的轉(zhuǎn)換
- 創(chuàng)建->活動(dòng)就緒:在當(dāng)前系統(tǒng)的性能和內(nèi)存容量均允許的狀態(tài)下創(chuàng)建進(jìn)程嘲叔;
- 創(chuàng)建->靜止就緒:不分配給新進(jìn)程所需資源(主要是內(nèi)存)亡呵,進(jìn)程被安置在外存不參與調(diào)度,進(jìn)程的創(chuàng)建工作尚未完成硫戈;
- 活動(dòng)就緒->靜止就緒:進(jìn)程處于未被掛起的就緒狀態(tài)時(shí)被掛起锰什,不參與調(diào)度;
- 靜止就緒->活動(dòng)就緒:靜止就緒狀態(tài)的進(jìn)程被激活丁逝,參與調(diào)度歇由;
- 活動(dòng)阻塞->靜止阻塞:進(jìn)程處于未被掛起的阻塞狀態(tài)時(shí)被掛起;
- 靜止阻塞->靜止就緒:靜止阻塞的進(jìn)程所期待的事件出現(xiàn)果港;
- 靜止阻塞->活動(dòng)阻塞:靜止阻塞狀態(tài)的進(jìn)程被激活。
進(jìn)程管理中的數(shù)據(jù)結(jié)構(gòu)
操作系統(tǒng)中用于管理控制的數(shù)據(jù)結(jié)構(gòu)
在計(jì)算機(jī)系統(tǒng)中糊昙,對于每個(gè)資源和每個(gè)進(jìn)程都設(shè)置了一個(gè)數(shù)據(jù)結(jié)構(gòu)辛掠,用于表征其實(shí)體,稱為資源信息表或進(jìn)程信息表释牺。OS管理的這些數(shù)據(jù)結(jié)構(gòu)一般分為內(nèi)存表萝衩、設(shè)備表、文件表和用于進(jìn)程管理的進(jìn)程表没咙,通常進(jìn)程表又被稱為進(jìn)程控制塊PCB猩谊。
PCB的作用
PCB的作用是使一個(gè)在多道程序環(huán)境下不能獨(dú)立運(yùn)行的程序(含數(shù)據(jù))稱為一個(gè)能獨(dú)立運(yùn)行的基本單位,一個(gè)能與其他進(jìn)程并發(fā)執(zhí)行的進(jìn)程祭刚。
- 作為獨(dú)立運(yùn)行的基本標(biāo)志
- 能實(shí)現(xiàn)間斷性運(yùn)行方式
- 提供進(jìn)程管理所需要的信息
- 提供進(jìn)程調(diào)度所需要的信息
- 實(shí)現(xiàn)與其他進(jìn)程的同步通信
PCB中的信息
- 進(jìn)程描述信息:包括進(jìn)程標(biāo)識(shí)符(用于標(biāo)志各個(gè)進(jìn)程)和用戶標(biāo)識(shí)符(用于標(biāo)志進(jìn)程歸屬的用戶牌捷,主要為共享和保護(hù)服務(wù));
- 進(jìn)程控制和管理信息:包括進(jìn)程的狀態(tài)涡驮、進(jìn)程優(yōu)先級等暗甥;
- 資源分配清單:用于說明有關(guān)內(nèi)存地址空間或虛擬空間的狀況,所打開的文件列表和所使用的輸入/輸出設(shè)備信息捉捅;
- 處理機(jī)相關(guān)信息:主要是處理機(jī)中各種寄存器的值撤防。
PCB的組織方式
- 線性方式:將所有的PCB都組織在一張線性表中,操作系統(tǒng)持有該線性表的首地址棒口;
- 鏈接方式:按照進(jìn)程狀態(tài)將PCB分為多個(gè)隊(duì)列寄月,操作系統(tǒng)持有指向各隊(duì)列的指針辜膝;
- 索引方式:按照進(jìn)程狀態(tài)的不同建立幾張索引表,操作系統(tǒng)持有指向各個(gè)索引表的指針漾肮。
進(jìn)程控制
進(jìn)程控制一般是由操作系統(tǒng)的內(nèi)核中的原語實(shí)現(xiàn)的厂抖。
操作系統(tǒng)內(nèi)核
現(xiàn)代操作系統(tǒng)一般將OS劃分為若干個(gè)層次,再將OS的不同功能分別設(shè)置在不同層次中初橘。通常將一些與硬件緊密相關(guān)的模塊(如中斷處理程序等)验游、各種設(shè)備的驅(qū)動(dòng)程序以及運(yùn)行頻率較高的模塊(如時(shí)鐘管理、進(jìn)程調(diào)度和許多模塊所公用的一些基本操作)都安排在緊靠硬件的軟件層次中保檐,將它們常駐內(nèi)存耕蝉,這些模塊被稱為內(nèi)核。
通常將處理機(jī)的狀態(tài)分為系統(tǒng)態(tài)和用戶態(tài)兩種:
- 系統(tǒng)態(tài):又稱為管態(tài)/內(nèi)核態(tài)/核心態(tài)夜只,具有較高的特權(quán)垒在,能執(zhí)行一切指令,訪問所有的寄存器和存儲(chǔ)區(qū)扔亥;
- 用戶態(tài):又稱為目態(tài)场躯,具有較低的特權(quán),僅能執(zhí)行規(guī)定的指令旅挤,訪問規(guī)定的寄存器和存儲(chǔ)區(qū)踢关。
一般情況下,應(yīng)用程序運(yùn)行在用戶態(tài)粘茄,操作系統(tǒng)內(nèi)核程序運(yùn)行在系統(tǒng)態(tài)签舞。
不同類型和規(guī)模的OS的內(nèi)核所包含的功能間存在一定的差異,但大多數(shù)OS內(nèi)核都包含支撐功能和資源管理功能兩大方面的功能柒瓣。
支撐功能
- 中斷處理:中斷處理是內(nèi)核最基本的功能儒搭,各種類型的系統(tǒng)調(diào)用、鍵盤命令的輸入芙贫、進(jìn)程調(diào)度搂鲫、設(shè)備驅(qū)動(dòng)等都依賴于中斷。為減少處理機(jī)中斷的時(shí)間磺平,提高程序執(zhí)行的并發(fā)性魂仍,內(nèi)核在對中斷進(jìn)行“有限處理”后便轉(zhuǎn)入相關(guān)進(jìn)程,由這些進(jìn)程完成后續(xù)處理工作拣挪;
- 時(shí)鐘管理:時(shí)鐘管理是內(nèi)核的一項(xiàng)基本功能蓄诽,時(shí)間片輪轉(zhuǎn)調(diào)度、實(shí)時(shí)系統(tǒng)中的截止時(shí)間控制媒吗、批處理系統(tǒng)中的最長運(yùn)行時(shí)間控制等都依賴于時(shí)鐘管理功能仑氛;
- 原語操作:原語是由若干條指令組成的,用于完成一定功能的一個(gè)過程,是一個(gè)原子操作(不可分割的基本單位)锯岖。原語在系統(tǒng)態(tài)執(zhí)行介袜,常駐內(nèi)存,在執(zhí)行過程中不允許被中斷出吹。鏈表操作遇伞、進(jìn)程同步、設(shè)備驅(qū)動(dòng)捶牢、CPU切換等功能都可以被定義為原語鸠珠。
資源管理功能
- 進(jìn)程管理:進(jìn)程狀態(tài)管理、進(jìn)程調(diào)度與分派秋麸、創(chuàng)建與撤銷PCB等渐排;
- 存儲(chǔ)器管理:存儲(chǔ)器空間的分配和回收、內(nèi)存信息保護(hù)灸蟆、代碼對換程序等驯耻;
- 設(shè)備管理:緩沖區(qū)管理、設(shè)備的分配和回收等炒考。
進(jìn)程控制
父進(jìn)程與子進(jìn)程
在OS中可缚,允許一個(gè)進(jìn)程創(chuàng)建另一個(gè)進(jìn)程,通常把創(chuàng)建者稱為父進(jìn)程斋枢,被創(chuàng)建者成為子進(jìn)程帘靡。子進(jìn)程可以繼承父進(jìn)程所擁有的資源(如父進(jìn)程打開的文件、分配到的緩沖區(qū)等)瓤帚,當(dāng)子進(jìn)程被撤銷時(shí)描姚,應(yīng)將其從父進(jìn)程那里獲得的資源歸還給父進(jìn)程。在撤銷父進(jìn)程時(shí)缘滥,必須同時(shí)撤銷其所有的子進(jìn)程。
進(jìn)程的創(chuàng)建
引起進(jìn)程創(chuàng)建的典型事件主要有:
- 用戶登錄:在分時(shí)系統(tǒng)中谒主,用戶登錄成功后操作系統(tǒng)將為該用戶創(chuàng)建一個(gè)進(jìn)程并插入就緒隊(duì)列中朝扼;
- 作業(yè)調(diào)度:在多道批處理系統(tǒng)中,當(dāng)作業(yè)調(diào)度程序按一定的算法調(diào)度到某些作業(yè)時(shí)霎肯,便將它們裝入內(nèi)存擎颖,為它們創(chuàng)建進(jìn)程,并將其插入就緒隊(duì)列观游;
- 提供服務(wù):當(dāng)運(yùn)行中的用戶程序提某種請求后(如要求進(jìn)行文件打印等)搂捧,操作系統(tǒng)將專門創(chuàng)建一個(gè)進(jìn)程提供用戶所需要的服務(wù);
- 應(yīng)用請求:用戶進(jìn)程自己創(chuàng)建新進(jìn)程懂缕,以便使新進(jìn)程以同創(chuàng)建者進(jìn)程并發(fā)運(yùn)行的方式完成特定任務(wù)允跑。
進(jìn)程的創(chuàng)建過程(創(chuàng)建原語)如下:
- 申請空白PCB,為新進(jìn)程創(chuàng)建一個(gè)唯一的進(jìn)程標(biāo)識(shí)號(hào),并從PCB集合中索取一個(gè)空白PCB聋丝;
- 為新進(jìn)程分配所需資源索烹,為新進(jìn)程的程序和數(shù)據(jù)及用戶棧分配必要的內(nèi)存空間(在PCB中體現(xiàn))。注意:若資源不足弱睦,則并不是創(chuàng)建失敗而是處于阻塞狀態(tài)百姓,等待所需資源;
- 初始化PCB况木,PCB的初始化過程主要包括:初始化標(biāo)識(shí)信息垒拢、初始化處理機(jī)狀態(tài)信息、初始化處理機(jī)控制信息火惊、設(shè)置進(jìn)程的優(yōu)先級等求类;
- 如果進(jìn)程就緒隊(duì)列能夠接納新進(jìn)程,便將新進(jìn)程插入就緒隊(duì)列矗晃。
進(jìn)程的終止
引起進(jìn)程終止的事件主要有:
- 正常結(jié)束:進(jìn)程的任務(wù)已經(jīng)完成并準(zhǔn)備退出運(yùn)行仑嗅;
- 異常結(jié)束:程序在運(yùn)行時(shí)發(fā)生了某種異常,使程序無法繼續(xù)運(yùn)行张症,如存儲(chǔ)區(qū)越界仓技、保護(hù)錯(cuò)、非法指令俗他、特權(quán)指令錯(cuò)脖捻、運(yùn)行超時(shí)、等待超時(shí)兆衅、算術(shù)運(yùn)算錯(cuò)地沮、I/O故障等;
- 外界干預(yù):進(jìn)程應(yīng)外界的請求而終止運(yùn)行羡亩,如操作員或操作系統(tǒng)干預(yù)摩疑、父進(jìn)程請求、父進(jìn)程終止等畏铆。
進(jìn)程的終止過程(撤銷原語)如下:
- 根據(jù)被終止的進(jìn)程標(biāo)識(shí)符雷袋,從PCB集合中檢索出該進(jìn)程的PCB,從中讀出該進(jìn)程的狀態(tài)辞居;
- 若被終止的進(jìn)程正處于執(zhí)行狀態(tài)則立即終止該進(jìn)程的執(zhí)行楷怒,并置調(diào)度標(biāo)志為真,用于指示該進(jìn)程被終止后重新進(jìn)行進(jìn)程調(diào)度瓦灶;
- 若該進(jìn)程還有子孫進(jìn)程則將其所有子孫進(jìn)程全部終止鸠删,以防它們成為不可控的進(jìn)程;
- 將被終止的進(jìn)程所擁有的全部資源歸還給其父進(jìn)程或者歸還給系統(tǒng)贼陶;
- 將被終止的進(jìn)程的PCB從所在隊(duì)列或鏈表中移出刃泡,等待其他程序來搜集信息巧娱。
進(jìn)程的阻塞與喚醒
引起進(jìn)程阻塞的原因:
- 申請共享資源失敗:進(jìn)程向系統(tǒng)申請資源時(shí),由于系統(tǒng)沒有足夠的資源分配給它而轉(zhuǎn)變?yōu)樽枞麪顟B(tài)捅僵;
- 等待某種操作的完成:當(dāng)進(jìn)程啟動(dòng)了某種操作后家卖,若該進(jìn)程必須在操作完成之后才能繼續(xù)執(zhí)行,則該進(jìn)程變?yōu)樽枞麪顟B(tài)等待操作完成庙楚;
- 新數(shù)據(jù)尚未到達(dá):對于相互合作的進(jìn)程上荡,如果一個(gè)進(jìn)程需要先獲得另一進(jìn)程提供的數(shù)據(jù)才能繼續(xù)執(zhí)行,如果所需數(shù)據(jù)尚未到達(dá)馒闷,進(jìn)程就處于阻塞狀態(tài)酪捡;
- 等待新任務(wù)的到達(dá):在某些系統(tǒng)中(特別是網(wǎng)絡(luò)環(huán)境下的OS),往往設(shè)置一些特定的系統(tǒng)進(jìn)程纳账,每當(dāng)它們完成任務(wù)后就變?yōu)樽枞麪顟B(tài)等待新任務(wù)的到來逛薇。
正在執(zhí)行的進(jìn)程如果發(fā)生了上述事件,進(jìn)程便通過調(diào)用阻塞原語block將自己阻塞疏虫,由此可見阻塞是進(jìn)程的一種主動(dòng)行為永罚。
進(jìn)程的阻塞過程(阻塞原語block)如下:
- 找到將要被阻塞的進(jìn)程的標(biāo)識(shí)號(hào)所對應(yīng)的PCB;
- 若該進(jìn)程處于運(yùn)行態(tài)卧秘,則保留其處理機(jī)狀態(tài)呢袱,將其運(yùn)行狀態(tài)改為阻塞態(tài)并停止運(yùn)行;
- 把該P(yáng)CB插入相應(yīng)事件的阻塞隊(duì)列翅敌,將處理機(jī)資源調(diào)度給其他就緒進(jìn)程并進(jìn)行切換羞福;
當(dāng)被阻塞進(jìn)程所期待的事件出現(xiàn)時(shí),則由有關(guān)進(jìn)程調(diào)用喚醒原語wakeup將等待該事件的進(jìn)程喚醒蚯涮。
進(jìn)程的喚醒過程(喚醒原語wakeup)如下:
- 在該事件的阻塞隊(duì)列中找到相應(yīng)進(jìn)程的PCB治专;
- 把該P(yáng)CB從阻塞隊(duì)列中移出,將其狀態(tài)設(shè)置為就緒態(tài)遭顶;
- 把該P(yáng)CB插入就緒隊(duì)列中张峰。
注意:block原語和wakeup原語是一對作用剛好相反的原語,必須成對使用棒旗;block原語是由被阻塞進(jìn)程自我調(diào)用實(shí)現(xiàn)的喘批,而wakeup原語則是由一個(gè)與被喚醒進(jìn)程合作或其他相關(guān)進(jìn)程的調(diào)用實(shí)現(xiàn)的。
進(jìn)程的掛起與激活
進(jìn)程的掛起過程(掛起原語suspend)如下:
- 檢查被掛起進(jìn)程的狀態(tài)嗦哆,若處于活動(dòng)狀態(tài)則置為靜止就緒態(tài)谤祖,若處于阻塞態(tài)則置為靜止阻塞態(tài)婿滓;
- 把該進(jìn)程的PCB復(fù)制到某指定的內(nèi)存區(qū)域老速,方便用戶或父進(jìn)程考查該進(jìn)程的運(yùn)行情況;
- 若被掛起的進(jìn)程正在執(zhí)行則重新進(jìn)行進(jìn)程調(diào)度凸主。
進(jìn)程的激活過程(激活原語active)如下:
- 將被激活的進(jìn)程從外存調(diào)入內(nèi)存橘券,檢查該進(jìn)程的狀態(tài),若為靜止就緒態(tài)則改為活動(dòng)就緒態(tài),若為靜止阻塞態(tài)則改為活動(dòng)阻塞態(tài)旁舰;
- 若采用搶占調(diào)度策略锋华,則根據(jù)被激活的進(jìn)程的優(yōu)先級檢查是否要重新進(jìn)行進(jìn)程調(diào)度;
- 若優(yōu)先級低則不重新調(diào)度箭窜,否則將處理機(jī)分配給被激活的進(jìn)程毯焕。
進(jìn)程切換
進(jìn)程切換指的是處理機(jī)從一個(gè)進(jìn)程的運(yùn)行轉(zhuǎn)到另一個(gè)進(jìn)程上運(yùn)行,在這個(gè)過程中磺樱,進(jìn)程的運(yùn)行環(huán)境產(chǎn)生了實(shí)質(zhì)性的變化纳猫。
進(jìn)程切換的過程如下:
- 保存處理機(jī)上下文,包括程序計(jì)數(shù)器PC和其他寄存器竹捉;
- 更新PCB信息芜辕;
- 把進(jìn)程的PCB移入相應(yīng)的隊(duì)列,如就緒隊(duì)列和某事件的阻塞隊(duì)列块差;
- 選擇另一個(gè)進(jìn)程執(zhí)行侵续,并更新其PCB;
- 更新內(nèi)存管理的數(shù)據(jù)結(jié)構(gòu)憨闰;
- 恢復(fù)處理機(jī)的上下文状蜗。
注意1:進(jìn)程切換與處理機(jī)模式切換(用戶態(tài)->內(nèi)核態(tài))不同,模式切換時(shí)處理機(jī)邏輯上可能還在統(tǒng)一進(jìn)程中運(yùn)行起趾。若進(jìn)程因中斷或異常而進(jìn)入核心態(tài)運(yùn)行诗舰,執(zhí)行完后又回到用戶態(tài)剛剛被中斷的程序運(yùn)行,則OS只需要恢復(fù)進(jìn)程進(jìn)入內(nèi)核時(shí)所保存的CPU現(xiàn)場训裆,而無需改變當(dāng)前進(jìn)程的環(huán)境信息眶根;若要切換進(jìn)程,當(dāng)前正在運(yùn)行的進(jìn)程發(fā)生了改變边琉,則當(dāng)前進(jìn)程的環(huán)境信息也需要改變属百。
注意2:進(jìn)程調(diào)度是決定處理機(jī)資源分配給哪個(gè)進(jìn)程的行為,是一種決策行為变姨;進(jìn)程切換是指世紀(jì)分配處理機(jī)的行為族扰,是一種執(zhí)行行為。一般來說定欧,先有資源的調(diào)度后有進(jìn)程切換渔呵。
進(jìn)程同步
進(jìn)程同步的基本概念
進(jìn)程同步機(jī)制的主要任務(wù),是對多個(gè)相關(guān)進(jìn)程在執(zhí)行次序上進(jìn)行協(xié)調(diào)砍鸠,使并發(fā)執(zhí)行的諸進(jìn)程之間能按照一定的規(guī)則(或時(shí)序)共享系統(tǒng)資源扩氢,并能很好地相互合作,從而使程序的執(zhí)行具有可再現(xiàn)性爷辱。
兩種形式的制約關(guān)系
- 直接相互制約關(guān)系:又稱同步录豺,是指為了完成某種任務(wù)而建立的兩個(gè)或多個(gè)進(jìn)程朦肘,這些進(jìn)程因?yàn)樾枰谀承┪恢蒙蠀f(xié)調(diào)它們的工作次序而等待、傳遞信息所產(chǎn)生的制約關(guān)系双饥。進(jìn)程間的直接制約關(guān)系來源于它們的相互合作媒抠;
- 間接相互制約關(guān)系:又稱互斥,當(dāng)一個(gè)進(jìn)程進(jìn)入臨界區(qū)訪問資源時(shí)咏花,另一個(gè)進(jìn)程必須等待趴生;當(dāng)占用臨界資源的進(jìn)程退出臨界區(qū)后,另一進(jìn)程才允許訪問此臨界資源昏翰。
在多道程序環(huán)境下冲秽,由于存在上述兩種相互制約的關(guān)系,進(jìn)程在運(yùn)行的過程中是否能獲得處理機(jī)運(yùn)行與以怎樣的速度運(yùn)行并不能由進(jìn)程自身所控制矩父,此即進(jìn)程的異步性锉桑。由此會(huì)產(chǎn)生對共享變量或數(shù)據(jù)結(jié)構(gòu)的不正確訪問次序,從而造成進(jìn)程每次執(zhí)行的結(jié)果不一致窍株。這種差錯(cuò)往往與時(shí)間有關(guān)民轴,故稱“與時(shí)間有關(guān)的錯(cuò)誤”。為了杜絕這種差錯(cuò)球订,必須對進(jìn)程的執(zhí)行次序進(jìn)行協(xié)調(diào)后裸,保證進(jìn)程能按順序執(zhí)行。
臨界資源
雖然多個(gè)進(jìn)程可以共享系統(tǒng)中的各種資源冒滩,但是許多硬件資源如打印機(jī)微驶、磁帶機(jī)等都屬于臨界資源;此外开睡,還有許多變量、數(shù)據(jù)等都可以被若干進(jìn)程共享篇恒,它們也屬于臨界資源胁艰。諸進(jìn)程之間應(yīng)采取互斥方式實(shí)現(xiàn)對這種資源的共享款筑。
臨界區(qū)
不論是硬件臨界資源還是軟件臨界資源,多個(gè)進(jìn)程必須互斥地對它們進(jìn)行訪問腾么,每個(gè)進(jìn)程中訪問臨界資源的那段代碼稱為臨界區(qū)奈梳。
為了保證臨界資源的正確使用,可以把臨界資源的訪問分為四個(gè)部分:
- 進(jìn)入?yún)^(qū):為了進(jìn)入臨界區(qū)使用臨界資源解虱,在進(jìn)入?yún)^(qū)要檢查可否進(jìn)入臨界區(qū)攘须,若能進(jìn)入臨界區(qū),則應(yīng)設(shè)置正在訪問臨界區(qū)的標(biāo)志饭寺,以阻止其他進(jìn)程同時(shí)進(jìn)入臨界區(qū)阻课;
- 臨界區(qū):進(jìn)程中訪問臨界資源的代碼,又稱臨界段艰匙;
- 退出區(qū):將正在訪問臨界區(qū)的標(biāo)志清除限煞;
- 剩余區(qū):代碼中的其余部分。
偽代碼:
do {
entry section; // 進(jìn)入?yún)^(qū)
critical section; // 臨界區(qū)
exit section; // 退出區(qū)
remainder section; // 剩余區(qū)
} while (true)
同步機(jī)制應(yīng)遵循的規(guī)則
所有同步機(jī)制都應(yīng)遵循以下四種原則:
- 空閑讓進(jìn):當(dāng)無進(jìn)程處于臨界區(qū)時(shí)员凝,表明臨界資源處于空閑狀態(tài)署驻,應(yīng)允許一個(gè)請求進(jìn)入臨界區(qū)的進(jìn)程立即進(jìn)入自己的臨界區(qū),以有效地利用臨界資源健霹;
- 忙則等待:當(dāng)有進(jìn)程已進(jìn)入臨界區(qū)時(shí)糖埋,表明臨界資源正在被訪問征候,其它試圖進(jìn)入臨界區(qū)的進(jìn)程必須等待,以保證對臨界資源的互斥訪問跑揉;
- 有限等待:對要求訪問臨界區(qū)的進(jìn)程,應(yīng)保證在有限時(shí)間內(nèi)能進(jìn)入自己的臨界區(qū),以避免陷入“死等”狀態(tài)甜无;
- 讓權(quán)等待:當(dāng)進(jìn)程不能進(jìn)入自己的臨界區(qū)時(shí),應(yīng)立即釋放處理機(jī),以避免進(jìn)程陷入“忙等”狀態(tài)寨蹋。
軟件實(shí)現(xiàn)方法
單標(biāo)志法
基本思想:設(shè)置一個(gè)公用整型變量turn
秸苗,用于指示被允許進(jìn)入臨界區(qū)的進(jìn)程編號(hào)。
偽代碼:
進(jìn)程P0:
while (turn != 0); // 進(jìn)入?yún)^(qū)
critical section; // 臨界區(qū)
turn = 1; // 退出區(qū)
remainder section; // 剩余區(qū)
進(jìn)程P1:
while (turn != 1); // 進(jìn)入?yún)^(qū)
critical section; // 臨界區(qū)
turn = 0; // 退出區(qū)
remainder section; // 剩余區(qū)
- 優(yōu)點(diǎn):可以保證每次只有一個(gè)進(jìn)程進(jìn)入臨界區(qū);
- 缺點(diǎn):兩個(gè)進(jìn)程必須交替進(jìn)入臨界區(qū)弧可;若某個(gè)進(jìn)程不再進(jìn)入臨界區(qū)氧秘,則另一個(gè)進(jìn)程也將無法進(jìn)入臨界區(qū)(違背“空閑讓進(jìn)”)搔确,容易造成資源利用不充分。
例如,若P0進(jìn)入臨界區(qū)并順利離開机隙,而P1不進(jìn)入臨界區(qū),turn = 1就會(huì)一直成立葱跋,P0就無法再次進(jìn)入臨界區(qū)。
雙標(biāo)志法先檢查
基本思想:在進(jìn)程進(jìn)入臨界區(qū)之前先檢查臨界資源是否正在被訪問模庐,如果是验庙,則該進(jìn)程需等待;否則,該進(jìn)程就可以進(jìn)入自己的臨界區(qū)藤巢。設(shè)置一個(gè)數(shù)據(jù)flag[i]
,第i
個(gè)元素為FALSE
表示Pi進(jìn)程沒有進(jìn)入臨界區(qū)绍刮,否則表示Pi進(jìn)程進(jìn)入臨界區(qū)得运。
偽代碼:
進(jìn)程Pi:
while (flag[j]); // (1)進(jìn)入?yún)^(qū)彬檀,此時(shí)flag[i] = FALSE
flag[i] = TRUE; // (3)進(jìn)入?yún)^(qū)
critical section; // 臨界區(qū)
flag[i] = FALSE; // 退出區(qū)
remainder section; // 剩余區(qū)
進(jìn)程Pj:
while (flag[i]); // (2)進(jìn)入?yún)^(qū)诽偷,此時(shí)flag[j] = FALSE
flag[j] = TRUE; // (4)進(jìn)入?yún)^(qū)
critical section; // 臨界區(qū)
flag[j] = FALSE; // 退出區(qū)
remainder section; // 剩余區(qū)
- 優(yōu)點(diǎn):進(jìn)程不需要交替進(jìn)入臨界區(qū)深浮,可連續(xù)使用菌瘫;
- 缺點(diǎn):Pi和Pj可能同時(shí)進(jìn)入臨界區(qū)忿等,若按(1)->(2)->(3)->(4)執(zhí)行時(shí)二者就會(huì)同時(shí)進(jìn)入臨界區(qū)(違背“忙則等待”)庵寞。
雙標(biāo)志法后檢查
基本思想:在“雙標(biāo)志法先檢查”的基礎(chǔ)上逸尖,進(jìn)程先將自己的標(biāo)志設(shè)置為TRUE
渐白,再檢測對方的狀態(tài)標(biāo)志,若對方的標(biāo)志為TRUE
則等待,否則進(jìn)入臨界區(qū)奕剃。
偽代碼:
進(jìn)程Pi:
flag[i] = TRUE; // (1)進(jìn)入?yún)^(qū)
while (flag[j]); // 進(jìn)入?yún)^(qū)
critical section; // 臨界區(qū)
flag[i] = FALSE; // 退出區(qū)
remainder section; // 剩余區(qū)
進(jìn)程Pj:
flag[j] = TRUE; // (2)進(jìn)入?yún)^(qū)
while (flag[i]); // 進(jìn)入?yún)^(qū)
critical section; // 臨界區(qū)
flag[j] = FALSE; // 退出區(qū)
remainder section; // 剩余區(qū)
- 優(yōu)點(diǎn):避免了“雙標(biāo)志法先檢查”同時(shí)進(jìn)入臨界區(qū)的問題肺然;
- 缺點(diǎn):若(1)和(2)幾乎同時(shí)執(zhí)行時(shí)悍缠,兩進(jìn)程的標(biāo)志都被置為
TRUE
滤港,雙方檢測對方狀態(tài)(執(zhí)行while
語句)時(shí)都無法進(jìn)入臨界區(qū),兩進(jìn)程無限期等待,造成“饑餓”現(xiàn)象缝龄;
Peterson's Algorithm
基本思想:在“雙標(biāo)志法后檢查”的基礎(chǔ)上重新設(shè)置變量turn
瞎饲,每個(gè)進(jìn)程設(shè)置自己的標(biāo)志后再設(shè)置turn
標(biāo)志妄田,然后同時(shí)檢測另一個(gè)進(jìn)程的狀態(tài)標(biāo)志和turn
標(biāo)志,以保證只能有一個(gè)進(jìn)程進(jìn)入臨界區(qū)。
偽代碼:
進(jìn)程Pi:
flag[i] = TRUE; turn = j; // 進(jìn)入?yún)^(qū)
while (flag[j] && turn == j); // 進(jìn)入?yún)^(qū)
critical section; // 臨界區(qū)
flag[i] = FALSE; // 退出區(qū)
remainder section; // 剩余區(qū)
進(jìn)程Pj:
flag[j] = TRUE; turn = i; // 進(jìn)入?yún)^(qū)
while (flag[i] && turn == i); // 進(jìn)入?yún)^(qū)
critical section; // 臨界區(qū)
flag[j] = FALSE; // 退出區(qū)
remainder section; // 剩余區(qū)
- 優(yōu)點(diǎn):解決了“饑餓”問題。
硬件同步機(jī)制
通過硬件支持實(shí)現(xiàn)臨界段問題的方法稱為低級方法薯演,或稱元方法。
中斷屏蔽方法
因?yàn)镃PU只在發(fā)生中斷時(shí)引起進(jìn)程切換愉镰,所以關(guān)中斷能保證當(dāng)前運(yùn)行的進(jìn)程讓臨界區(qū)的代碼順利地執(zhí)行完。其典型模式為:
關(guān)中斷
臨界區(qū)
開中斷
這種方法降低了處理機(jī)交替執(zhí)行程序的能力,因此執(zhí)行的效率會(huì)明顯降低讼渊。對內(nèi)核來說,在它執(zhí)行更新變量或列表的幾條指令時(shí)關(guān)中斷是很方便的,但是將關(guān)中斷的權(quán)利交給用戶則很不明智奶甘。
硬件指令方法
依靠TestAndSet
和Swap
兩條由硬件直接實(shí)現(xiàn)的、不會(huì)被中斷的指令完成钉赁。
TestAndSet
指令的功能描述如下:
boolean TestAndSet(boolean *lock) {
boolean old;
old = *lock;
*lock = true;
return old;
}
可以為每個(gè)臨界資源設(shè)置一個(gè)共享布爾變量lock
邑蒋,初值為false
,該變量的值為true
表示資源正在被占用束莫。在進(jìn)程訪問臨界資源前策严,利用TestAndSet
指令檢查和修改標(biāo)志lock
。偽代碼如下:
while (TestAndSet(&lock));
critical section;
lock = false;
remainder section;
Swap
指令的功能描述如下:
Swap(boolean *a, boolean *b) {
boolean temp;
temp = *a;
*a = *b;
*b = temp;
}
該指令的功能是交換兩個(gè)字(字節(jié))的內(nèi)容倔韭。
應(yīng)為每個(gè)臨界資源設(shè)置一個(gè)共享布爾變量lock
,初值為false
醇疼,在每個(gè)進(jìn)程中再設(shè)置一個(gè)局部變量key
壶栋,初值為true
,用于與lock
交換信息毙玻。在進(jìn)入臨界區(qū)前,先利用Swap
指令交換lock
和key
的內(nèi)容运准,然后檢查key
的狀態(tài)米者,有進(jìn)程在臨界區(qū)時(shí)胰丁,重復(fù)檢查和交換過程机蔗,直到進(jìn)程退出幔嗦。偽代碼如下:
key = true;
while (key != false) {
Swap(&lock, &key);
}
critical section;
lock = false;
remainder section;
硬件同步機(jī)制的優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn):
- 不管是單處理機(jī)還是多處理機(jī)嬉挡,都適用于任意數(shù)目的進(jìn)程因谎;
- 簡單风皿、容易驗(yàn)證其正確性;
- 可以支持進(jìn)程內(nèi)有多個(gè)臨界區(qū)魔眨,只需為每個(gè)臨界區(qū)設(shè)置一個(gè)布爾變量。
- 缺點(diǎn):
- 進(jìn)程等待進(jìn)入臨界區(qū)時(shí)要耗費(fèi)處理機(jī)時(shí)間,不能實(shí)現(xiàn)讓權(quán)等待侥啤;
- 由于是從等待進(jìn)程中隨機(jī)選擇一個(gè)進(jìn)入臨界區(qū),有的進(jìn)程可能一直得不到調(diào)度醉箕,從而導(dǎo)致“饑餓”現(xiàn)象姻报;
信號(hào)量機(jī)制
信號(hào)量機(jī)制是一種功能較強(qiáng)的機(jī)制,可用來解決互斥與同步問題治拿,它只能被兩個(gè)標(biāo)準(zhǔn)的原語wait(S)
和signal(S)
訪問嚷掠,也可記為P操作和V操作未檩。
原語是指完成某種功能且不可被分割孙蒙、不能被中斷的執(zhí)行序列,可由硬件實(shí)現(xiàn)透典,在單處理機(jī)上可通過軟件屏蔽中斷的方法實(shí)現(xiàn)凑队。
整型信號(hào)量
整型信號(hào)量被定義為一個(gè)表示資源數(shù)目的整型量S
西壮,wait
和signal
操作如下:
wait (S) {
while (S <= 0);
S -= 1;
}
signal (S) {
S += 1;
}
在wait
操作中霍狰,只要信號(hào)量S <= 0
可都,就會(huì)不斷測試(while循環(huán))。因此蚓耽,該機(jī)制未遵循“讓權(quán)等待”而是使進(jìn)程處于“忙等”狀態(tài)渠牲。
記錄型信號(hào)量
記錄型信號(hào)量除了需要一個(gè)用于代表資源數(shù)目的整型變量value
外,還需要再增加一個(gè)進(jìn)程鏈表L
谚咬,用于鏈接所有等待該資源的進(jìn)程辑鲤。
記錄型信號(hào)量可描述為:
typedef struct {
int value;
struct process *L;
} semaphore;
相應(yīng)的wait
礁击、signal
操作如下:
void wait(semaphore S) { // 相當(dāng)于申請資源
S.value--;
if (S.value < 0) {
add this process to S.L;
block(S.L);
}
}
void signal(semaphore S) {
S.value++;
if (S.value <= 0) {
remove a process P from S.L;
wakeup(P);
}
}
wait
操作:S.value--
表示進(jìn)程請求該類資源漩勤,當(dāng)S.value < 0
時(shí)表示該類資源已經(jīng)分配完畢,此時(shí)進(jìn)程調(diào)用block
原語進(jìn)行自我阻塞酬滤,放棄處理機(jī)译打,并加入該類資源的等待隊(duì)列L
搪缨。因此奏篙,該機(jī)制遵循了“讓權(quán)等待”原則炸茧。
signal
操作:進(jìn)程釋放了一個(gè)資源,S.value++
表示系統(tǒng)中可供分配的資源數(shù)量加1形导,若加1后仍然是S.value <= 0
锰霜,則表示S.L
中還有等待該資源的進(jìn)程被阻塞焚刺,因此還應(yīng)調(diào)用wakeup
原語浅役,將S.L
中一個(gè)等待該資源的進(jìn)程喚醒。
可以理解為P操作是獲取鎖衅斩,V操作是釋放鎖蒜田。
利用信號(hào)量實(shí)現(xiàn)進(jìn)程同步
設(shè)P2中的語句y需要使用進(jìn)程P1中的語句x的運(yùn)行結(jié)果(即語句y必須在語句x之后執(zhí)行)隆豹,利用信號(hào)量實(shí)現(xiàn)進(jìn)程同步的算法如下:
semaphore S = 0; // 初始化信號(hào)量
P1() {
...
x; // 語句x
V(S); // 釋放鎖(告訴進(jìn)程P2府寒,x語句已完成)
...
}
P2() {
...
P(S); // 獲取鎖(檢查語句x是否運(yùn)行完成)
y; // 語句y
...
}
總結(jié):前V后P
利用信號(hào)量實(shí)現(xiàn)進(jìn)程互斥
只需要把臨界區(qū)置于P(S)和V(S)之間,就可以實(shí)現(xiàn)兩個(gè)進(jìn)程對資源的互斥訪問。算法如下:
semaphore S = 1; // 初始化信號(hào)量
P1() {
...
P(S); // 準(zhǔn)備開始訪問臨界資源,加鎖
進(jìn)程P1的臨界區(qū);
V(S); // 訪問結(jié)束初嘹,解鎖
...
}
P2() {
...
P(S); // 加鎖
進(jìn)程P2的臨界區(qū);
V(S); // 解鎖
...
}
總結(jié):若某個(gè)行為要用到某種資源窃躲,要先對這種資源執(zhí)行P操作褐桌;若某個(gè)行為會(huì)提供某種資源,需要先對這種資源執(zhí)行V操作延赌,即在臨界區(qū)前后分別P、V
利用信號(hào)量實(shí)現(xiàn)前趨關(guān)系
設(shè)有如下前趨圖:
其中S1叉橱,S2挫以,...,S6都是最簡單的程序段(只有一條語句)窃祝。為使各個(gè)程序段能正確執(zhí)行掐松,應(yīng)設(shè)置若干個(gè)初始值為“0”的信號(hào)量。如為保證S1 -> S2, S1 -> S3的前趨關(guān)系粪小,應(yīng)分別設(shè)置信號(hào)量a大磺、b;同樣探膊,為保證S2 -> S4, S2 -> S5, S3 -> S6, S4 -> S6, S5 -> S6的前趨關(guān)系杠愧,應(yīng)設(shè)置信號(hào)量c、d逞壁、e流济、f锐锣、g。算法如下:
p1() {
S1;
signal(a);
signal(b);
}
p2() {
wait(a);
S2;
signal(c);
signal(d);
}
p3() {
wait(b);
S3;
signal(e);
}
p4() {
wait(c);
S4;
signal(f);
}
p5() {
wait(d);
S5;
signal(g);
}
p6() {
wait(e);
wait(f);
wait(g);
S6;
}
main() {
semaphore a, b, c, d, e, f, g;
a.value = b.value = c.value = 0;
d.value = e.value = 0;
f.value = g.value = 0;
cobegin
p1();
p2();
p3();
p4();
p5();
p6();
coend
}
管程
定義
系統(tǒng)中的各種硬件資源和軟件資源均可利用數(shù)據(jù)結(jié)構(gòu)抽象地描述其資源特性绳瘟,即用少量信息和對該資源所執(zhí)行的操作來表征該資源刺下,而忽略它們的內(nèi)部結(jié)構(gòu)和實(shí)現(xiàn)細(xì)節(jié)。因此稽荧,可以利用共享數(shù)據(jù)結(jié)構(gòu)抽象地表示系統(tǒng)中的共享資源橘茉,并且將對該共享數(shù)據(jù)結(jié)構(gòu)實(shí)施的特定操作定義為一組過程(函數(shù)),進(jìn)程對共享資源的申請姨丈、釋放和其它操作必須通過這組過程間接地對共享數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)操作畅卓。代表共享資源的數(shù)據(jù)結(jié)構(gòu)及由對該共享數(shù)據(jù)結(jié)構(gòu)實(shí)施操作的一組過程所組成的資源管理程序共同構(gòu)成了一個(gè)操作系統(tǒng)的資源管理模塊,稱為管程蟋恬。管程定義了一個(gè)數(shù)據(jù)結(jié)構(gòu)和能為并發(fā)進(jìn)程所執(zhí)行(在該數(shù)據(jù)結(jié)構(gòu)上)的一組操作翁潘,這組操作能同步進(jìn)程改變管程中的數(shù)據(jù)。
管程由四部分組成:
- 管程的名稱
- 局部于管程內(nèi)部的共享數(shù)據(jù)結(jié)構(gòu)說明歼争;
- 對該數(shù)據(jù)結(jié)構(gòu)進(jìn)行操作的一組過程(或函數(shù))拜马;
- 對局部于管程的共享數(shù)據(jù)結(jié)構(gòu)設(shè)置初值的語句。
管程的定義描述舉例如下:
monitor Demo { // 定義一個(gè)名稱為“Demo”的管程
// 定義共享數(shù)據(jù)結(jié)構(gòu)沐绒,對應(yīng)系統(tǒng)中的某些共享資源
共享數(shù)據(jù)結(jié)構(gòu)S;
// 對共享數(shù)據(jù)結(jié)構(gòu)的初始化的語句
init_code() {
S = 5; // 初始資源數(shù)等于5
}
// 過程1: 申請一個(gè)資源
take_away() {
對共享數(shù)據(jù)結(jié)構(gòu)S的一系列處理俩莽;
S--; // 可用資源數(shù)-1
...
}
// 過程2: 歸還一個(gè)資源
give_back() {
對共享數(shù)據(jù)結(jié)構(gòu)S的一系列處理;
S++; // 可用資源數(shù)+1
...
}
}
實(shí)際上乔遮,管程包含了面向?qū)ο蟮乃枷耄?/p>
- 管程把對共享資源的操作封裝起來扮超,管程內(nèi)部的共享數(shù)據(jù)結(jié)構(gòu)只能被管程的過程所訪問,一個(gè)進(jìn)程只有通過調(diào)用管程內(nèi)的過程才能進(jìn)入管程訪問共享資源蹋肮;
- 每次僅允許一個(gè)進(jìn)程進(jìn)入管程出刷,從而實(shí)現(xiàn)進(jìn)程互斥(由編譯器實(shí)現(xiàn))。
從語言的角度來看坯辩,管程主要有以下特征:
- 模塊化:管程是一個(gè)基本的程序單位馁龟,可單獨(dú)編譯;
- 抽象數(shù)據(jù)類型:管程中不僅有數(shù)據(jù)漆魔,還有對數(shù)據(jù)的操作坷檩;
- 信息掩蔽:管程中的數(shù)據(jù)結(jié)構(gòu)只能被管程中的過程訪問,這些過程也是在管程內(nèi)部定義的有送,供管程外的進(jìn)程調(diào)用淌喻,而管程中的數(shù)據(jù)結(jié)構(gòu)和過程(函數(shù))的具體實(shí)現(xiàn)外部不可見。
管程和進(jìn)程的不同:
- 雖然二者都定義了數(shù)據(jù)結(jié)構(gòu)雀摘,但進(jìn)程定義是私有數(shù)據(jù)結(jié)構(gòu)PCB裸删,管程定義的是公共數(shù)據(jù)結(jié)構(gòu),如消息隊(duì)列等阵赠;
- 二者都存在對各自數(shù)據(jù)結(jié)構(gòu)上的操作涯塔,但進(jìn)程是由順序程序執(zhí)行的有關(guān)操作肌稻,而管程主要是進(jìn)行同步操作和初始化操作;
- 設(shè)置進(jìn)程的目的在于實(shí)現(xiàn)系統(tǒng)的并發(fā)性匕荸,設(shè)置管程的目的是解決共享資源的互斥使用問題爹谭;
- 進(jìn)程通過調(diào)用管程中的過程對共享數(shù)據(jù)結(jié)構(gòu)實(shí)行操作,該過程就如通常的子程序一樣被調(diào)用榛搔,因而管程為被動(dòng)工作方式诺凡,進(jìn)程為主動(dòng)工作方式;
- 進(jìn)程間能并發(fā)執(zhí)行践惑,而管程則不能與其調(diào)用者并發(fā)腹泌;
- 進(jìn)程具有動(dòng)態(tài)性,管程則是操作系統(tǒng)中的一個(gè)資源管理模塊尔觉,供進(jìn)程調(diào)用凉袱。
條件變量
當(dāng)一個(gè)進(jìn)程調(diào)用了管程,在管程中被阻塞或掛起侦铜,直到阻塞或掛起的原因解除专甩。而在此期間,如果該進(jìn)程不釋放管程钉稍,則其他進(jìn)程無法進(jìn)入管程涤躲,被迫長時(shí)間等待。為了解決這個(gè)問題嫁盲,引入了條件變量condition
篓叶。通常,一個(gè)進(jìn)程被阻塞或掛起的條件(原因)可有多個(gè)羞秤,因此在管程中設(shè)置了多個(gè)條件變量,對這些條件變量的訪問只能在管程中進(jìn)行左敌。
管程中對每個(gè)條件變量都必須予以說明瘾蛋,其形式為:condition x, y;
對條件變量的操作僅僅是wait
和signal
,因此條件變量也是一種抽象數(shù)據(jù)類型矫限,每個(gè)條件變量保存了一個(gè)鏈表哺哼,用于記錄因該條件變量而阻塞的所有進(jìn)程,同時(shí)提供的兩個(gè)操作可以表示為x.wait
和x.signal
叼风。其含義為:
-
x.wait:正在調(diào)用管程的進(jìn)程因x條件需要被阻塞或掛起取董,則調(diào)用
x.wait
將自己插入到x條件的等待隊(duì)列上,并釋放管程无宿,直到x條件變化茵汰。此時(shí)其他進(jìn)程可以使用該管程。 -
x.signal:正在調(diào)用管程的進(jìn)程發(fā)現(xiàn)x條件發(fā)生了變化孽鸡,則調(diào)用
x.signal
重新啟動(dòng)一個(gè)因x條件而被阻塞或掛起的進(jìn)程蹂午,如果存在多個(gè)這樣的進(jìn)程栏豺,則選擇其中的一個(gè),如果沒有豆胸,繼續(xù)執(zhí)行原進(jìn)程奥洼,而不產(chǎn)生任何結(jié)果。
條件變量的定義和使用如下:
monitor Demo {
共享數(shù)據(jù)結(jié)構(gòu)S;
condition x; // 定義一個(gè)條件變量x
init_code() {
...
}
take_away() {
if (S <= 0) {
x.wait(); // 資源不夠晚胡,在條件變量x上阻塞等待
}
資源足夠灵奖,分配資源,做一系列相應(yīng)處理估盘;
}
give_back() {
歸還資源瓷患,做一系列相應(yīng)處理;
if (有進(jìn)程在等待) {
x.signal(); // 喚醒一個(gè)阻塞進(jìn)程
}
}
}
條件變量與信號(hào)量的比較:
- 相似點(diǎn):條件變量的wait/signal操作類似于信號(hào)量的P/V操作忿檩,可以實(shí)現(xiàn)進(jìn)程的阻塞/喚醒尉尾;
- 不同點(diǎn):條件變量是“沒有值”的,僅實(shí)現(xiàn)了“排隊(duì)等待”功能燥透;信號(hào)量是“有值”的沙咏,信號(hào)量的值反映了剩余資源數(shù),而在管程中班套,剩余資源數(shù)用共享數(shù)據(jù)結(jié)構(gòu)記錄肢藐。
經(jīng)典進(jìn)程的同步問題
進(jìn)程同步PV操作題分析步驟:
- 關(guān)系分析:找出題目中各個(gè)進(jìn)程,分析它們之間同步吱韭、互斥的關(guān)系吆豹;
- 整理思路:根據(jù)各進(jìn)程的操作流程確定P、V操作的大致順序理盆;
- 信號(hào)量設(shè)置:設(shè)置需要的信號(hào)量痘煤,并根據(jù)題目確定信號(hào)量初值(互斥信號(hào)量初值一般為1,同步信號(hào)量初值要看系統(tǒng)中資源初始數(shù)目多少)猿规。
生產(chǎn)者-消費(fèi)者問題
問題描述
系統(tǒng)中有一組生產(chǎn)者進(jìn)程和一組消費(fèi)者進(jìn)程共享一個(gè)公用緩沖池衷快,緩沖池中具有n個(gè)緩沖區(qū),只有緩沖池沒滿的時(shí)候姨俩,生產(chǎn)者進(jìn)程才能把消息放入緩沖區(qū)蘸拔,否則必須等待;只有緩沖池不空時(shí)环葵,消費(fèi)者才能從中取出消息调窍,否則必須等待。由于緩沖池是臨界資源张遭,它只允許一個(gè)生產(chǎn)者放入消息或一個(gè)消費(fèi)者從中取出消息邓萨。
代碼
semaphore mutex = 1; // 互斥信號(hào)量,實(shí)現(xiàn)對緩沖區(qū)的互斥訪問
semaphore empty = n; // 同步信號(hào)量,表示空閑緩沖區(qū)的數(shù)量
semaphore full = 0; // 同步信號(hào)量先誉,表示非空閑緩沖區(qū)的數(shù)量(消息的數(shù)量)
producer() { // 生產(chǎn)者進(jìn)程的任務(wù)是:不斷地生產(chǎn)產(chǎn)品湿刽,并放入緩沖區(qū)
while (1) {
生產(chǎn)一個(gè)消息;
P(empty); // 消費(fèi)一個(gè)空閑緩沖區(qū)
P(mutex); // 進(jìn)入臨界區(qū),獲取緩沖池的鎖(互斥信號(hào)量)
把消息放入緩沖區(qū);
V(mutex); // 離開臨界區(qū)褐耳,釋放緩沖池的鎖(互斥信號(hào)量)
V(full); // 釋放一個(gè)滿的緩沖區(qū)(釋放一個(gè)消息)
}
}
consumer() {
while (1) { // 消費(fèi)者進(jìn)程的任務(wù)是:不斷地取出緩沖區(qū)中的消息诈闺,然后消費(fèi)掉
P(full); // 消費(fèi)一個(gè)滿緩沖區(qū)(消費(fèi)一個(gè)消息)
P(mutex); // 進(jìn)入臨界區(qū),獲取緩沖池的鎖
從緩沖區(qū)中取出一個(gè)消息;
V(mutex); // 離開臨界區(qū)铃芦,釋放緩沖池的鎖
V(empty); // 釋放一個(gè)空緩沖區(qū)
消費(fèi)消息;
}
}
注意:生產(chǎn)者-消費(fèi)者問題的易錯(cuò)點(diǎn)在于:在生產(chǎn)者-消費(fèi)者問題中雅镊,實(shí)現(xiàn)互斥的P操作必須在實(shí)現(xiàn)同步的P操作之后,否則會(huì)出現(xiàn)死鎖刃滓;因?yàn)閂操作不會(huì)導(dǎo)致進(jìn)程阻塞仁烹,所以V操作的順序無所謂,先釋放哪一個(gè)都可以咧虎。
注意2:如果緩沖區(qū)大小為1卓缰,有可能不需要設(shè)置互斥信號(hào)量mutex就可以實(shí)現(xiàn)互斥訪問緩沖區(qū)的功能,但是需要具體問題具體分析(當(dāng)然加上了也沒有問題)砰诵。
讀者-寫者問題
讀者-寫者問題為解決復(fù)雜的互斥問題提供了一個(gè)參考思路:設(shè)置互斥訪問的計(jì)數(shù)器變量count
來記錄當(dāng)前正在訪問文件的進(jìn)程數(shù)征唬,可以用count
的值判斷是第一個(gè)或最后一個(gè)讀進(jìn)程并做不同處理(加鎖、解鎖等)茁彭。如果對count
變量的檢查和賦值不能“一氣呵成”會(huì)導(dǎo)致一些錯(cuò)誤总寒,就需要用到互斥信號(hào)量實(shí)現(xiàn)“一氣呵成”。
問題描述
有讀者和寫者兩組并發(fā)進(jìn)程理肺,共享一個(gè)文件摄闸。當(dāng)兩個(gè)以上的讀進(jìn)程同時(shí)訪問共享數(shù)據(jù)時(shí)不會(huì)產(chǎn)生副作用,但若某個(gè)寫進(jìn)程和其他進(jìn)程(讀或?qū)戇M(jìn)程)同時(shí)訪問共享數(shù)據(jù)時(shí)則可能導(dǎo)致數(shù)據(jù)不一致的錯(cuò)誤妹萨。因此要求:
- 允許多個(gè)讀者可以同時(shí)對文件執(zhí)行讀操作年枕;
- 只允許一個(gè)寫者往文件中寫信息;
- 任一寫者完成寫操作之前不允許其它讀者或?qū)懻吖ぷ鳎?/li>
- 寫者執(zhí)行操作前乎完,應(yīng)讓已有的讀者和寫者全部退出画切。
代碼
- 讀進(jìn)程優(yōu)先:只要有源源不斷的讀進(jìn)程在讀文件,寫進(jìn)程就需要一直阻塞等待囱怕,可能會(huì)導(dǎo)致寫進(jìn)程“餓死”的情況。
int count = 0; // 用于記錄當(dāng)前有幾個(gè)讀進(jìn)程在訪問文件
semaphore rw = 1; // 用于實(shí)現(xiàn)對共享文件的互斥訪問
semaphore mutex = 1; // 用于實(shí)現(xiàn)對count變量的互斥訪問毫别,使得對count變量的檢查和賦值可以“一氣呵成”
writer() { // 寫進(jìn)程的工作很簡單:開始寫之前對共享文件加鎖娃弓,寫完后釋放鎖
while (1) {
P(rw); // 獲取共享文件的鎖
寫文件;
V(rw); // 釋放共享文件的鎖
}
}
reader() { // 不同的讀進(jìn)程要負(fù)責(zé)加鎖和解鎖
while (1) {
P(mutex); // 獲取count變量的鎖
if (count == 0) { // 第一個(gè)讀進(jìn)程要負(fù)責(zé)加鎖
P(rw); // 獲取共享文件的鎖
}
count++; // 加鎖完成,讀者計(jì)數(shù)器加1
V(mutex); // 釋放count變量的鎖
讀文件;
P(mutex); // 獲取count變量的鎖
count--; // 讀文件完成岛宦,讀者計(jì)數(shù)器減1
if (count == 0) { // 最后一個(gè)讀進(jìn)程負(fù)責(zé)解鎖
V(rw); // 釋放共享文件的鎖
}
V(mutex); // 釋放count變量的鎖
}
}
- 寫進(jìn)程優(yōu)先/讀寫公平法:有寫進(jìn)程請求訪問時(shí)台丛,應(yīng)禁止后續(xù)讀進(jìn)程的請求,且在無寫進(jìn)程的情況下才允許讀進(jìn)程再次運(yùn)行。
int count = 0; // 用于記錄當(dāng)前有幾個(gè)讀進(jìn)程在訪問文件
semaphore rw = 1; // 用于實(shí)現(xiàn)對共享文件的互斥訪問
semaphore mutex = 1; // 用于實(shí)現(xiàn)對count變量的互斥訪問挽霉,使得對count變量的檢查和賦值可以“一氣呵成”
semaphore w = 1; // 用于實(shí)現(xiàn)“寫優(yōu)先”
writer() { // 寫進(jìn)程的工作很簡單:開始寫之前對共享文件加鎖防嗡,寫完后釋放鎖
while (1) {
P(w); // 獲取寫進(jìn)程的鎖
P(rw); // 獲取共享文件的鎖
寫文件;
V(rw); // 釋放共享文件的鎖
V(w); // 釋放寫進(jìn)程的鎖
}
}
reader() { // 不同的讀進(jìn)程要負(fù)責(zé)加鎖和解鎖
while (1) {
P(w); // 獲取寫進(jìn)程的鎖
P(mutex); // 獲取count變量的鎖
if (count == 0) { // 第一個(gè)讀進(jìn)程要負(fù)責(zé)加鎖
P(rw); // 獲取共享文件的鎖
}
count++; // 加鎖完成,讀者計(jì)數(shù)器加1
V(mutex); // 釋放count變量的鎖
V(w); // 釋放寫進(jìn)程的鎖侠坎,讓其它讀/寫進(jìn)程可以訪問共享文件
讀文件;
P(mutex); // 獲取count變量的鎖
count--; // 讀文件完成蚁趁,讀者計(jì)數(shù)器減1
if (count == 0) { // 最后一個(gè)讀進(jìn)程負(fù)責(zé)解鎖
V(rw); // 釋放共享文件的鎖
}
V(mutex); // 釋放count變量的鎖
}
}
注意:這種算法中寫者不會(huì)“饑餓”,但也不是真正的“寫優(yōu)先”实胸,而是相對公平的先來先服務(wù)原則他嫡。
哲學(xué)家進(jìn)餐問題
哲學(xué)家進(jìn)餐問題的關(guān)鍵在于解決進(jìn)程死鎖。這些進(jìn)程之間存在互斥關(guān)系庐完,但是與之前接觸到的互斥關(guān)系不同的地方在于每個(gè)進(jìn)程都需要同時(shí)持有兩個(gè)臨界資源钢属,因此就有產(chǎn)生死鎖的隱患。如果遇到了一個(gè)進(jìn)程需要同時(shí)持有多個(gè)臨界資源的情況门躯,應(yīng)該參考哲學(xué)家進(jìn)餐問題的思想淆党,分析進(jìn)程中是否會(huì)發(fā)生循環(huán)等待(是否會(huì)發(fā)生死鎖)。
問題描述
一張圓桌邊上坐著五名哲學(xué)家讶凉,每兩名哲學(xué)家之間的桌上擺上一根筷子染乌,兩根筷子中間是一碗米飯。哲學(xué)家們傾注畢生精力思考和進(jìn)餐缀遍,哲學(xué)家在思考時(shí)慕匠,并不影響他人。只有當(dāng)哲學(xué)家饑餓時(shí)域醇,才試圖拿起左台谊、右兩根筷子(一根一根地拿起)。若筷子已在他人手上譬挚,則需要等待锅铅。饑餓的哲學(xué)家只有同時(shí)拿到了兩根筷子才可以開始進(jìn)餐,進(jìn)餐完畢后减宣,放下筷子繼續(xù)思考盐须。
代碼
哲學(xué)家按順序編號(hào)為0~4,哲學(xué)家i左邊的筷子編號(hào)為i
漆腌,右邊的筷子編號(hào)為(i + 1) % 5
- 可能產(chǎn)生死鎖的情況:5名哲學(xué)家都想要進(jìn)餐并分別拿起左邊筷子時(shí)贼邓,再想要拿起右邊筷子時(shí)就會(huì)被阻塞,產(chǎn)生了死鎖闷尿。
semaphore chopstick[5] = {1, 1, 1, 1, 1};
Pi() { // i號(hào)哲學(xué)家的進(jìn)程
do {
P(chopstick[i]); // 取左邊筷子
P(chopstick[(i + 1) % 5]); // 取右邊筷子
進(jìn)餐;
V(chopstick[i]); // 放下左邊筷子
V(chopstick[(i + 1) % 5]); // 放下右邊筷子
思考;
} while (1);
}
- 不會(huì)產(chǎn)生死鎖的情況
semaphore chopstick[5] = {1, 1, 1, 1, 1};
semaphore mutex = 1; // 互斥取筷子的信號(hào)量
Pi() {
do {
P(mutex); // 獲得互斥量的鎖
P(chopstick[i]); // 取左邊筷子
P(chopstick[(i + 1) % 5]); // 取右邊筷子
V(mutex); // 釋放互斥量的鎖
進(jìn)餐;
V(chopstick[i]); // 放下左邊筷子
V(chopstick[(i + 1) % 5]); // 放下右邊筷子
思考;
} while (1);
}
吸煙者問題
吸煙者問題為解決“可以生產(chǎn)多個(gè)產(chǎn)品的單生產(chǎn)者”問題提供了一個(gè)思路塑径。關(guān)鍵在于如何用整型變量i
實(shí)現(xiàn)輪流操作(類似于循環(huán)隊(duì)列中計(jì)算當(dāng)前指針位置時(shí)模隊(duì)列長度的操作)。若一個(gè)生產(chǎn)者要生產(chǎn)多種產(chǎn)品填具,那么各個(gè)V操作應(yīng)該放在各自對應(yīng)的“事件”發(fā)生之后的位置统舀。
問題描述
假設(shè)一個(gè)系統(tǒng)有三個(gè)抽煙者進(jìn)程和一個(gè)供應(yīng)者進(jìn)程。每個(gè)抽煙者不停地卷煙并抽掉它,但要卷起一支煙誉简,抽煙者需要有三種材料:煙草碉就、紙和膠水。三個(gè)抽煙者中闷串,第一個(gè)擁有煙草瓮钥,第二個(gè)擁有紙,第三個(gè)擁有膠水窿克。供應(yīng)者無限地提供三種材料骏庸,供應(yīng)者每次將兩種材料放到桌子上,擁有剩下那種材料的抽煙者卷一根煙并抽掉它年叮,并給供應(yīng)者一個(gè)信號(hào)告訴已完成具被,此時(shí)供應(yīng)者就會(huì)將另外兩種材料放到桌上,如此重復(fù)(讓三個(gè)抽煙者輪流地抽煙)只损。
代碼
int i = 0; // 用于實(shí)現(xiàn)“三個(gè)抽煙者輪流抽煙”
semaphore offer1 = 0; // 桌上煙草和紙組合的數(shù)量
semaphore offer2 = 0; // 桌上煙草和膠水組合的數(shù)量
semaphore offer3 = 0; // 桌上紙和膠水組合的數(shù)量
semaphore finish = 0; // 抽煙是否完成
provider() { // 擁有煙草的抽煙者
while (1) {
i = (i + 1) % 3; // 實(shí)現(xiàn)循環(huán)提供三種組合一姿,即“三個(gè)抽煙者輪流抽煙”
if (i == 0) {
V(offer1); // 提供煙草和紙
} else if (i == 1) {
V(offer2); // 提供煙草和膠水
} else if (i == 2) {
V(offer3); // 提供紙和膠水
}
把兩種材料放在桌子上;
P(finish); // 等待抽煙者的完成信號(hào)
}
}
smoker1() { // 擁有煙草的抽煙者
while (1) {
P(offer3);
從桌子上拿走紙和膠水,卷成煙跃惫,抽掉叮叹;
V(finish);
}
}
smoker2() { // 擁有紙的抽煙者
while (1) {
P(offer2);
從桌子上拿走煙草和膠水,卷成煙爆存,抽掉;
V(finish);
}
}
smoker3() { // 擁有膠水的抽煙者
while (1) {
P(offer1);
從桌子上拿走煙草和紙蛉顽,卷成煙,抽掉;
V(finish);
}
}
進(jìn)程通信
進(jìn)程通信指的是進(jìn)程之間的信息交換先较。
進(jìn)程的互斥與同步只能稱為低級通信携冤,原因如下:
- 效率低:生產(chǎn)者每次只能向緩沖池投放一個(gè)產(chǎn)品(消息),消費(fèi)者每次只能從緩沖區(qū)中取得一個(gè)消息闲勺;
- 通信對用戶不透明:OS只為進(jìn)程間的通信提供了共享存儲(chǔ)器曾棕,關(guān)于進(jìn)程之間通信所需的共享數(shù)據(jù)的設(shè)置、數(shù)據(jù)的傳送菜循、進(jìn)程的互斥與同步都需要程序員自己實(shí)現(xiàn)翘地。
在進(jìn)程間需要傳送大量數(shù)據(jù)時(shí),應(yīng)該使用高級通信方式癌幕,主要特點(diǎn)為:
- 使用方便:通信過程對用戶是透明的衙耕;
- 高效地傳送大量數(shù)據(jù):用戶可以直接利用高級通信命令(原語)高效地傳送大量數(shù)據(jù)。
共享存儲(chǔ)器系統(tǒng)
在共享存儲(chǔ)器系統(tǒng)中勺远,相互通信的進(jìn)程共享某些數(shù)據(jù)結(jié)構(gòu)或共享存儲(chǔ)區(qū)臭杰,進(jìn)程之間能通過這些空間進(jìn)行通信。共享存儲(chǔ)器系統(tǒng)分為兩種類型:
- 基于共享數(shù)據(jù)結(jié)構(gòu)的通信方式/低級方式:進(jìn)程公用某些數(shù)據(jù)結(jié)構(gòu)借以實(shí)現(xiàn)進(jìn)程之間的信息交換谚中。這種方式通信效率低下,屬于低級通信;
- 基于共享存儲(chǔ)區(qū)的通信方式/高級方式:在內(nèi)存中劃出一塊共享存儲(chǔ)區(qū)域宪塔,進(jìn)程可通過對該共享區(qū)的讀或?qū)懡粨Q信息實(shí)現(xiàn)通信磁奖,OS只負(fù)責(zé)為通信進(jìn)程提供可共享使用的存儲(chǔ)空間和同步互斥工具,而數(shù)據(jù)交換則由用戶自己安排讀/寫指令完成某筐。
管道通信系統(tǒng)
管道是用于連接一個(gè)讀進(jìn)程和一個(gè)寫進(jìn)程以實(shí)現(xiàn)它們之間通信的一個(gè)共享文件比搭,又名pipe文件。
向管道(共享文件)提供輸入的發(fā)送進(jìn)程(寫進(jìn)程)以字符流的方式將數(shù)據(jù)送入管道南誊,接收管道輸出的接收進(jìn)程(讀進(jìn)程)則從管道中接收(讀)數(shù)據(jù)身诺。
為了協(xié)調(diào)上方的通信,管道機(jī)制必須提供以下三方面的協(xié)調(diào)能力:
- 互斥:當(dāng)一個(gè)進(jìn)程正在對管道進(jìn)行讀/寫操作時(shí)另一進(jìn)程必須等待抄囚;
- 同步:當(dāng)寫進(jìn)程把一定數(shù)量的數(shù)據(jù)寫入管道后便去等待霉赡,直到讀進(jìn)程取走數(shù)據(jù)后再喚醒;當(dāng)讀進(jìn)程讀空管道時(shí)也應(yīng)等待幔托,直到寫進(jìn)程將數(shù)據(jù)寫入管道后再喚醒穴亏;
- 確定對方是否存在:只有確定對方已存在時(shí)才能進(jìn)行通信。
注意:管道是半雙工通信的重挑,要事項(xiàng)全雙工通信需要兩個(gè)管道嗓化。
消息傳遞系統(tǒng)
在該機(jī)制中,進(jìn)程不必借助任何共享存儲(chǔ)區(qū)或數(shù)據(jù)結(jié)構(gòu)谬哀,而是以格式化的消息為單位將通信的數(shù)據(jù)封裝在消息中刺覆,并利用操作系統(tǒng)提供的一組通信命令(原語)在進(jìn)程間進(jìn)行消息傳遞,完成進(jìn)程間的數(shù)據(jù)交換史煎。
消息傳遞系統(tǒng)因?qū)崿F(xiàn)方式不同可分為兩類:
- 直接通信方式:發(fā)送進(jìn)程利用OS所提供的發(fā)送原語直接把消息發(fā)送給目標(biāo)進(jìn)程谦屑;
- 間接通信方式:發(fā)送和接收進(jìn)程都通過中間實(shí)體(郵箱)的方式進(jìn)行消息的發(fā)送和接收。
線程(Threads)的基本概念
線程的引入
引入進(jìn)程的目的是更好地使多道程序并發(fā)執(zhí)行劲室,提高資源利用率和系統(tǒng)吞吐量伦仍;引入線程的目的是減小程序在并發(fā)執(zhí)行時(shí)所付出的時(shí)空開銷,使OS具有更好的并發(fā)性很洋。
由于線程擁有許多傳統(tǒng)進(jìn)程所具有的特征充蓝,所以又被稱為“輕型進(jìn)程”,它是一個(gè)基本的CPU執(zhí)行單元喉磁,也是程序執(zhí)行流的最小單元谓苟,是進(jìn)程中的一個(gè)實(shí)體,是被系統(tǒng)獨(dú)立調(diào)度和分派的基本單位协怒。
- 線程自己不擁有系統(tǒng)資源涝焙,它與同屬一個(gè)進(jìn)程的其它線程共享自己擁有的全部資源;
- 一個(gè)線程可以創(chuàng)建和撤銷另一個(gè)線程孕暇,同一個(gè)進(jìn)程中的多個(gè)線程可以并發(fā)執(zhí)行仑撞;
- 由于線程之間相互制約赤兴,線程在運(yùn)行中也具有間斷性;
- 線程也有就緒隧哮、運(yùn)行桶良、阻塞三種狀態(tài)。
引入線程后沮翔,進(jìn)程只作為除CPU外的系統(tǒng)資源的分配單元陨帆,線程作為處理機(jī)的分配單元。
線程與進(jìn)程的比較
- 調(diào)度的基本單位:在傳統(tǒng)的OS中采蚀,進(jìn)程是作為獨(dú)立調(diào)度和分派的基本單位疲牵,也是能獨(dú)立運(yùn)行的基本單位。引入線程后榆鼠,線程是獨(dú)立單獨(dú)和分派的基本單位和能獨(dú)立運(yùn)行的基本單位纲爸,進(jìn)程是擁有資源的基本單位。線程切換時(shí)僅需保存和設(shè)置少量寄存器內(nèi)容璧眠,切換代價(jià)遠(yuǎn)低于進(jìn)程缩焦;在同一進(jìn)程中切換線程不會(huì)引起進(jìn)程的切換,從一個(gè)進(jìn)程的線程切換到另一個(gè)進(jìn)程中的線程時(shí)會(huì)引起進(jìn)程的切換责静;
- 并發(fā)性:在引入線程的OS中袁滥,不僅進(jìn)程之間可以并發(fā)執(zhí)行,線程之間也可以并發(fā)執(zhí)行灾螃,這使得OS具有更好的并發(fā)性题翻,從而能更加有效地提高系統(tǒng)資源的利用率和系統(tǒng)的吞吐量;
- 擁有資源:進(jìn)程是擁有資源的基本單位腰鬼,線程本身不擁有系統(tǒng)資源嵌赠,而僅有一點(diǎn)必不可少的、能獨(dú)立運(yùn)行的資源熄赡,比如在每個(gè)線程中應(yīng)具有一個(gè)線程控制塊TCB姜挺、程序計(jì)數(shù)器、保留局部變量彼硫、少數(shù)狀態(tài)參數(shù)和返回地址等的一組寄存器和堆棧炊豪。線程除了擁有自己的少量資源外,還允許多個(gè)線程共享該進(jìn)程所擁有的資源拧篮,如已打開的文件尖淘、定時(shí)器止剖、信號(hào)量機(jī)構(gòu)等的內(nèi)存空間和進(jìn)程申請到的I/O設(shè)備等;
- 獨(dú)立性:在同一進(jìn)程中的不同線程之間的獨(dú)立性要比不同進(jìn)程之間的獨(dú)立性低得多蔫劣。不同進(jìn)程的地址空間相互獨(dú)立油啤,同一進(jìn)程的不同線程共享進(jìn)程的內(nèi)存地址空間和資源冕广,進(jìn)程內(nèi)的線程對其他進(jìn)程不可見;進(jìn)程間通信需要進(jìn)程同步互斥手段來保證數(shù)據(jù)的一致性,而線程間可以直接讀/寫進(jìn)程數(shù)據(jù)段(如全局變量)進(jìn)行通信慧妄;
- 系統(tǒng)開銷:在創(chuàng)建和撤銷進(jìn)程時(shí),系統(tǒng)都要為之分配和回收PCB纫溃、內(nèi)存空間和I/O設(shè)備等資源腰涧,因此OS為此所付出的開銷明顯大于線程創(chuàng)建和撤銷時(shí)所付出的開銷;此外紊浩,由于一個(gè)進(jìn)程中的多個(gè)線程具有相同的地址空間,線程之間的同步和通信也比進(jìn)程簡單疗锐,在一些OS中坊谁,線程的切換、同步和通信都無需操作系統(tǒng)內(nèi)核的干預(yù)滑臊;
- 支持多處理機(jī)系統(tǒng):在多處理機(jī)系統(tǒng)中口芍,對于傳統(tǒng)的進(jìn)程,不管有多少處理機(jī)雇卷,該進(jìn)程都只能運(yùn)行在一個(gè)處理機(jī)上鬓椭;引入線程后,就可以將一個(gè)進(jìn)程中的多個(gè)線程分配到多個(gè)處理機(jī)上关划,使它們并行執(zhí)行小染,加快了進(jìn)程的執(zhí)行速度。
線程的屬性
多線程操作系統(tǒng)把線程作為獨(dú)立運(yùn)行或調(diào)度的基本單位贮折,此時(shí)進(jìn)程已經(jīng)不是一個(gè)基本的可執(zhí)行實(shí)體裤翩,進(jìn)程的“執(zhí)行”狀態(tài)實(shí)際上指的是進(jìn)程中的線程正在執(zhí)行。
線程的主要屬性如下:
- 線程不擁有系統(tǒng)資源调榄,每個(gè)線程擁有一個(gè)唯一的標(biāo)識(shí)符和一個(gè)線程控制塊TCB踊赠,線程控制塊記錄了線程執(zhí)行的寄存器和棧現(xiàn)場等信息每庆;
- 不同的線程可以執(zhí)行相同的程序筐带;
- 同一進(jìn)程中的不同線程共享該進(jìn)程所擁有的系統(tǒng)資源;
- 線程是處理機(jī)調(diào)度的基本單位缤灵,多個(gè)線程可以并發(fā)執(zhí)行伦籍;
- 線程在生命周期內(nèi)會(huì)經(jīng)歷就緒態(tài)、運(yùn)行態(tài)凤价、阻塞態(tài)等各種狀態(tài)的變化鸽斟。
線程的實(shí)現(xiàn)
線程有兩種實(shí)現(xiàn)方式:用戶級線程(ULT)和內(nèi)核級線程(KLT)。內(nèi)核級線程又稱為內(nèi)核支持的線程利诺。
在用戶級線程中富蓄,有關(guān)線程管理的所有工作都由應(yīng)用程序完成,內(nèi)核意識(shí)不到線程的存在慢逾,應(yīng)用程序可以使用線程庫設(shè)計(jì)成多線程程序立倍。
在內(nèi)核級線程中灭红,線程的管理工作由內(nèi)核完成,應(yīng)用程序沒有線程管理的代碼口注,只有一個(gè)內(nèi)核級線程的編程接口变擒,內(nèi)核為進(jìn)程及其內(nèi)部的每個(gè)線程維護(hù)上下文信息,調(diào)度也在內(nèi)核基于線程架構(gòu)的基礎(chǔ)上完成寝志。
有些系統(tǒng)中使用組合的方式的多線程實(shí)現(xiàn)娇斑,線程的創(chuàng)建在用戶空間中完成,線程的調(diào)度與同步也在應(yīng)用程序中進(jìn)行材部,一個(gè)應(yīng)用程序中的多個(gè)用戶級線程被映射到一些內(nèi)核級線程上毫缆。
多線程模型
多線程模型即用戶級線程和內(nèi)核級線程的連接方式。
- 多對一模型:將多個(gè)用戶級線程映射到一個(gè)內(nèi)核級線程上乐导,線程的管理在用戶空間完成苦丁。此模式中用戶級線程對操作系統(tǒng)不可見。優(yōu)點(diǎn):線程管理是在用戶空間進(jìn)行的物臂,效率較高旺拉;缺點(diǎn):一個(gè)線程在使用內(nèi)核服務(wù)時(shí)被阻塞會(huì)導(dǎo)致整個(gè)進(jìn)程被阻塞,多個(gè)線程不能很好地運(yùn)行在多處理機(jī)上棵磷;
- 一對一模型:每個(gè)用戶級線程映射到一個(gè)內(nèi)核級線程蛾狗。優(yōu)點(diǎn):一個(gè)線程被阻塞后另一個(gè)線程可以繼續(xù)執(zhí)行,并發(fā)能力較強(qiáng)泽本;缺點(diǎn):每創(chuàng)建一個(gè)用戶級線程都要?jiǎng)?chuàng)建一個(gè)內(nèi)核級線程淘太,創(chuàng)建線程的開銷比較大,會(huì)對應(yīng)用程序的性能造成影響规丽;
- 多對多模型:將n個(gè)用戶級線程映射到m個(gè)內(nèi)核級線程上蒲牧,m <= n。優(yōu)點(diǎn):既克服了多對一模型并發(fā)度不高的缺點(diǎn)赌莺,又克服了一對一模型創(chuàng)建進(jìn)程開銷較大的缺點(diǎn)冰抢,此外還擁有多對一模型和一對一模型的優(yōu)點(diǎn)。