進程的描述與控制
- 1.前趨圖與程序執行
- 1.1 前趨圖介紹:
- 描述程序先后執行順序,又稱為有向無循環圖,可記為DAG(Directed Acyclic Graph)
- 如進程Pi與進程Pj存在著前趨關系,可寫為Pi -> Pj(或(Pi,Pj)),表示在Pj開始前Pi必須完成,這里稱Pi為Pj的直接前趨,Pj為Pi的直接后繼,在前趨圖中,沒有直接前趨的點稱為初始節點(Initial Node),沒有直接后繼的點稱為終止節點(Final Node)
- 需要注意的是,前趨圖是不允許有循環的,原因可從定義中找,如S1->S2->S3,不能要求S2和S3之間還有循環,這個循環是指,在上圖的前提下,又要求S2執行前要求S3必須執行完成
- 1.2 程序順序執行
- 順序執行的特征:
- 順序性:每一個操作必須在上一個操作結束之后才能開始
- 封閉性:程序運行時,獨占本機資源,執行結果不受外界干擾
- 可再現性:只要程序初始條件和環境相同,重復執行,結果都相同
- 順序執行的特征:
- 1.3 程序并發執行
- 特征:
- 間斷性:并發的程序會有相互制約的關系,在程序運行時,會具有"執行--暫停--執行"這種間斷性的活動規律
- 失去封閉性:并發執行時,由于系統的資源被這些并發程序共享,資源狀態會被這些程序改變,所以導致某一程序運行時,他的運行環境必然受到其他程序的影響
- 不可再現性:失去了封閉性,那么資源狀態也不穩定,所以也會失去可再現性
- 特征:
- 1.1 前趨圖介紹:
- 2.進程的描述
-
2.1 定義與特征
為了使參與并發執行的每個程序都能獨立的運行,在操作系統中都為其配置一個專門的數據結構->進程控制塊(Process Control Block,PCB)。使用PCB來描述進程的基本情況和活動過程,進而控制管理進程
程序段、相關的數據段和PCB構成了進程實體(進程映像),一般簡稱進程實體為進程
創建進程,撤銷進程,都指的是創建進程實體中的PCB和撤銷進程實體中的PCB
-
定義:
- 進程是程序的一次執行
- 進程是一個程序機器數據在處理機上順序執行時所發生的活動
- 進程是具有獨立功能的程序在一個數據集合上運行的過程,是系統進行資源調度和分配的一個獨立單元
- 一句話:進程是進程實體的運行過程,是系統進行資源分配和調度的一個獨立單位
-
特征:
- 動態性:進程的實質是進程實體的運行過程,動態性是進程的最基本的特征;具有"創建而產生,調度而執行,撤銷而消亡",即進程實體具有一定的生命期,而程序指示一段有序指令的集合,并存放在某種介質上,即靜態的
- 并發性:指多個進程實體共存于內存中,且能在一段時間內同時運行。引入進程目的就是為了使進程實體能與其他進程實體并發執行
- 獨立性:指進程實體是一個能獨立運行,獨立獲得資源和獨立接受調度的基本單位
- 異步性:指進程是按照異步方式運行的,即按照各自獨立的、不可預知的速度向前推進
-
進程的基本狀態
- 就緒(Ready)狀態:指進程已分配到除CPU外的所有必要資源,只要獲得CPU,便可立即執行。即進程已處于準備好運行的狀態
- 執行(Running)狀態:指進程已獲得CPU,其程序正在執行的狀態
- 阻塞(Block)狀態:指正在進行的進程受到某事件(I/O請求,申請緩存區失敗等)暫時無法繼續執行時的狀態。此時引起進程調度,OS將處理機分配給另一個就緒隊列中的就緒進程,將這個阻塞進程處于暫停階段,稱這個暫停狀態為阻塞狀態,阻塞狀態的進程大于一個時,會排成一份隊列,稱為阻塞隊列
-
三種基本狀態的轉化
三種基本狀態的轉化- 創建狀態和終止狀態
- 創建狀態:進程由創建而產生。創建步驟:①進程申請一個空白PCB②向PCB中填寫用于控制和管理進程的信息③為進程分配所必須的資源④將進程轉入到就緒狀態插入到就緒隊列中。若進程創建所需資源不足時,進程不能被調度運行,因為創建工作尚未完成,把這個狀態稱為創建狀態
- 終止狀態:終止步驟:①等待OS進行善后處理②將PCB清零③將PCB空間返還系統
- 創建狀態和終止狀態
-
掛起操作和進程狀態的轉換
- 掛起操作:當掛起操作作用于某個進程時,該進程將被掛起,意味著進入靜止狀態,若該進程正在執行,將暫停執行,若原本處于就緒狀態,將不接受調度。與掛起操作對應的是激活操作
- 掛起狀態的引入
- 終端用戶的需要
- 父進程的請求
- 負荷調節的需要
- 操作系統的需要
- 引入掛起操作或激活操作后,三個基本進程狀態的轉換
- 活動就緒->靜止就緒(引入掛起)
- 活動阻塞->靜止阻塞(引入掛起)
- 靜止就緒->活動就緒(引入激活)
- 靜止阻塞->活動阻塞(引入激活)
- 引入掛起操作后五個進程狀態的轉換
- NULL -> 創建
- 創建 -> 活動就緒
- 創建 -> 靜止就緒
-
執行 -> 終止
Snip20170109_1.png
-
進程管理中的數據結構
- 操作系統中用于管理控制的數據結構
數據結構:為了便于對計算機中的各類資源(硬件和信息等)的使用和管理,OS將他們抽象為相應的各種數據結構,并提供一組對資源進行操作的命令,用戶可利用這些數據結構及操作命令來執行相應的操作,而無需關心他們實現的具體細節。
-
OS中用于管理控制的數據結構
-
OS中,對每個資源和進程都設置了一個數據結構,來表征其實體。包含了資源或進程的表示、描述、狀態等信息和指針。通過指針,可以進行分類,便于OS查找
Snip20170109_3.png
-
-
進程表(進程控制塊PCB)
- 作用:
- 作為獨立運行基本單位的標志:OS是通過PCB去感知進程的存在,PCB已經成為進程存在于系統的中唯一標志
- 能實現間斷性運行方式:在多道程序環境下,程序是間斷性運行,所以進程必須要保留運行時的CPU現場信息,再次被調度運行時,還需恢復CPU現場信息,這個信息保留在PCB中
- 提供進程管理所需要的信息:進程被調度時,根據PCB中記錄的程序和數據在內存或外存中的始址地址,找到程序和數據。
- 提供進程調度所需要的信息:進程只有在就緒狀態才能被調度運行,而這種進程的狀態信息就是存儲在PCB中,另外比如優先級,已執行時間等等也是在PCB中
- 實現與其他進程的同步和通信:PCB中具有用于實現進程通信的區域和通信隊列指針等
- PCB中的信息(主要)
- 進程標識符
- 外部標識符:為了方便用戶(進程)對進程的訪問,由創建者提供,一般由數字、字母組成
- 內部標識符:方便系統對進程的使用,賦予每個進程一個唯一的數字標識符,通常是進程的序號
- 處理機狀態
- 主要由處理機中的各種寄存器中的內容組成,這些寄存器包括①通用寄存器②指令計數器③程序狀態字PSW④用戶棧指針
- 進程調度信息
- 進程狀態
- 進程優先級
- 進程調度所需其他信息,如進程已執行時間、等待CPU時間總和等
- 事件:指進程狀態由執行->阻塞所發生的事件,即阻塞原因
- 進程控制信息
- 指用于進程控制所需要的必須信息:①程序和數據的指針②進程同步和通信機制③資源清單④鏈接指針(給出了PCB所在隊列的下一個進程的PCB首地址)
- 進程標識符
- PCB的組織方式
- 線性方式:將系統中所有PCB都組織在一張線性表中,將該表的首址存放在內存中的專用區域中。優點:簡單,開銷小。缺點:每次查找都要掃描整張表
- 鏈接方式:把相同狀態進程的PCB分別通過PCB中鏈接字鏈接成一個隊列。就會形成就緒隊列、空白隊列、若干阻塞隊列等,隊列中,往往會進行優先級排列
- 索引方式:根據所有進程狀態的不同,建立幾張索引表,如就緒索引表、阻塞索引表等,并把各索引表的首地址存在內存中一些專用單元中
- 作用:
- 操作系統中用于管理控制的數據結構
-
- 3.進程控制
- 進程控制主要包括哪些:創建、終止、阻塞、狀態轉換等,一般是通過OS中內核的原語實現
- OS內核:
- 一些與硬件緊密相關的模塊、各種常用設備的驅動程序以及運行效率較高的模塊,安排在僅靠硬件的軟件層次中,并常駐內存,這些通常被稱為OS的內核,安排OS內核的目的:①便于保護這些軟件,防止被篡改②提高OS的運行效率
- OS內核主要功能:
- 支撐功能:
- 中斷處理:是內核最基本的功能,是OS賴以活動的基礎,為了提高程序執行的并發性,減少處理機中斷的過程,內核對中斷進行“有效處理”后,便轉入相關的進程
- 時鐘管理:是內核的基本功能。如時間片輪的調度中,時間片用完時,時鐘管理產生一個中斷信號,使調度程序重新調度
- 原語操作:原語->若干條指令組成,用于完成一定功能的一個過程。與其他的過程區別在于:是“原子操作”。(原子操作->一個操作中所有動作要么全做,要么全不做。也就是說是一個不可分割的基本單位)。因為原語的特性,所以原語執行過程中不允許被打斷。原語有:對鏈表操作的原語、用來實現進程同步的原語等
- 資源管理功能:
- 進程管理:由于進程管理中的各個功能模塊調用頻率高或者被其他功能模塊所需要,為了提高OS性能,將他們都放在內核中
- 存儲器管理:存儲器管理軟件的運行頻率較高,放在內核中,來保證存儲器管理具有較高的運行速度
- 設備管理:因為設備管理與硬件(設備)緊密相關,所以大部分都設置在內核中。如驅動程序、來緩和CPU和I/O速度不匹配矛盾的緩沖管理等模塊
- 支撐功能:
- 進程的創建
- 進程的層次結構:OS中允許進程創建另一個進程,創建進程的進程->父進程,被創建的進程->子進程,子進程可創建更多的孫進程等,形成一個進程家族。子進程可繼承父進程的資源,撤銷父進程也會撤銷其所有的子進程;需要注意的是:Windows中不存在進程層次結構的概念,所有進程地位都相同,而是獲得句柄有否,控制與被控制的簡單關系
- 進程圖:為了形象地描述一個進程的家族關系引入來描述進程間關系的有向樹
- 引起創建進程的事件:使程序之間并發運行,需要分別建立進程。導致進程創建進程的事件有:
- 用戶登錄:分時系統中,終端鍵入登錄命令,成功就建立一個進程,并插入就緒隊列
- 作業調度:多道批處理系統中,調度到某個作業時,便裝入內存,創建進程,并插入就緒隊列
- 提供服務:當運行中的用戶程序提出某種請求后,系統將專門創建一個進程來滿足用戶提出的服務,如打印請求
- 應用請求:以上三種都是系統內核為用戶創建的進程,而這類事件是用戶進程自己創建新進程
- 進程的創建: OS調用進程創建原語Creat按照下述四個步驟創建新進程
- 申請空白PCB:為新進程申請唯一的數字標志符,并從PCB集合中索取一個空白PCB
- 為新進程分配其運行所需資源:如內存、文件、I/O設備和CPU時間等,這些從OS或者父進程中獲取
- 初始化PCB:包括①初始化標識信息②初始化處理機狀態信息③初始化處理機控制信息
- 若進程就緒隊列可以接納這個新進程,就插入到就緒隊列
- 進程的終止
- 引起進程終止的事件
- 正常結束
- 異常結束
- 外界干預
- 進程的終止過程
- 根據被終止進程的標識符,從PCB集合中檢索出該進程的PCB,從PCB中讀取進程狀態
- 若該進程狀態處于執行狀態,應立即終止該進程的執行,并置換調度標志為真,代表該進程終止后應重新進行調度
- 若該進程還有子孫進程,還應將所有子孫進程都終止
- 將被終止的進程所擁有的資源歸還于父進程或者系統
- 將被終止的進程PCB從所在隊列(或鏈表)中移出,等待其他程序來搜集信息
- 引起進程終止的事件
- 進程的阻塞和喚醒
- 引起進程阻塞和喚醒的事件
- 向系統請求共享資源失敗
- 等待某種操作的完成
- 新數據尚未到達
- 等待新任務的到達
- 進程阻塞過程:正在執行的進程,發生了上述事件,便調用阻塞原語Block將自己阻塞,所以阻塞是一種自身行為
- 進程喚醒過程:當被阻塞進程發生了所期待的事件,由有關進程調用喚醒原語wakeup,將這個進程喚醒:①將被阻塞進程從等待改時間的阻塞隊列中移出②將其PCB中的現行狀態由阻塞改為就緒③將PCB插入到就緒隊列中
- 注意:block原語與wakeup原語是必須成對使用,即使用了block原語,必須在相關進程中安排一條對應的wakeup原語
- 引起進程阻塞和喚醒的事件
- 進程的掛起和激活
- 進程的掛起:執行過程:①檢查被掛起進程狀態,活動就緒->靜止就緒,活動阻塞->靜止阻塞②把該進程的PCB復制到某指定的內存區域,這是為了方便用戶或父進程檢查其運行情況③若該進程正在運行,則轉向調度程序重新調度
- 進程的激活過程:執行過程:①檢查被激活進程狀態,靜止就緒->活動就緒,靜止阻塞->活動阻塞②若執行的是搶占調度策略,就由調度程序將被激活進程與當前進程優先級比較,選擇高的運行
- 4.進程的同步
- 引入同步原因:OS引入進程后,既能提高系統的吞吐量,也能提高系統的資源利用率,但是也使得系統的變得復雜,如果不對多個進程進行妥善管理,那么這些進程就會對資源的無序爭奪造成混亂,所以要引入進程同步機制,來使得多個進程有條不紊的執行
- 進程同步的基本概念
- 兩種形式的制約關系
- 間接相互制約關系
- 多個程序在并發執行時,由于共享系統資源,比如CPU,I/O設備等,導致這些并發程序之間存在著相互制約關系。另外對于打印機、磁帶機這些只有一個的臨界資源,必須保證多個進程對他的訪問時互斥的。對于系統中這些資源,用戶要使用,首先申請,不能任由用戶進程隨意直接使用
- 直接相互制約關系
- 某些應用程序,為了完成任務而創建了多個進程,這些進程為了完成同一項任務而相互合作。直接相互制約關系就源于它們之間的相互合作。如輸入進程A和計算進程B,B會等待A的輸入后開始執行
- 間接相互制約關系
- 臨界資源
- 一些硬件資源比如打印機、磁帶機等,都是臨界資源,另外除了上述的硬件臨界資源還有軟件臨界資源。并發進程間應采取互斥方式,來實現對此資源的共享
- 臨界區(critical section)
- 把每個進程中訪問臨界資源的代碼稱為臨界區。①進入區:臨界區前面增加的用來檢查臨界資源是否正在被訪問的代碼②臨界區:不再解釋③退出區:臨界區后面加上的代碼,來修改代表臨界資源正被訪問的標志為未被訪問的標志④剩余區:除了進入區、臨界區、退出區之外的其他部分代碼
- 同步機制應遵循的規則
- 空閑讓進
- 忙則等待
- 有限等待
- 讓權等待
- 兩種形式的制約關系
- 硬件同步機制
- 關中斷
是實現互斥最簡單的方法之一。進入鎖 測試之前關閉中斷,完成鎖測試并上鎖后才能打開中斷。即進程在臨界區執行時,OS不相應中斷,也就不會調度進程,也就不會進程切換。缺點:①濫用關中斷權利可能造成嚴重后果②若時間過長,會影響系統性能③不適用于多CPU系統,因為一個CPU上關中斷不能防止進程在其他處理器上執行相同的臨界區代碼
-
使用Swap指令實現進程互斥
void swap(boolean *a,boolean *b){ boolean temp; temp = *a; *a = *b; *b = temp; } // 實現進程互斥偽代碼 boolean lock = FALSE; do{ boolean key = TRUE; do{ swap(&lock,key); }while(key!=FALSE); 臨界區操作 lock = FALSE; ... }while(TRUE);
- 關中斷
- 信號量機制
- 整形信號量
-
最初的設計:把整形信號量定義為表示資源數目的整形量S,不同于一般整形量,只能通過兩個標準的原子操作wait(S)、singal(S)來訪問,被稱為P、V操作
wait(S){ while(s<=0); // do no operation S--; } singal(S){ S++; }
-
- 記錄性信號量
- 采用記錄性的數據結構得名,包含兩個數據項:表示資源數目的整形變量Value,進程鏈表指針list
- AND型信號量
- 針對一個進程需要獲得多個共享資源后才執行任務等情況
- 信號量集
- 對AND型信號量機制擴充所得,每次可以對臨界資源進行一個單位的申請和釋放,擴充為可一次申請N個單位
- 整形信號量
- 信號量的應用
- 管程機制
- 管程(Monitors):一個數據結構和該數據結構上能被并發進程所執行的一組操作
- 進程同步的基本概念
如下圖:
- 進程對共享資源的訪問都是通過這組過程對共享數據結構的操作來實現,這組過程根據資源的使用情況,接受或者阻塞進程對共享資源的訪問,確保同一時間只有一個進程訪問共享資源,實現進程的互斥
- 管程的結構:
TYPE<管程名> = MONITOR
// 在管程內部的數據結構,只能被管程內部的過程訪問;反之,管程內部的過程也只能訪問管程內的數據結構
<共享變量說明>;
procedure<過程名>(<形式參數表>);
begin
<過程體>;
end;
....
procedure<過程名>(<形式參數表>);
begin
<過程體>;
end;
begin<管程的局部數據初始化語句序列>;
end;
- 管程相當于圍墻,把共享變量和對他操作的若干過程圍起來,所有過程要訪問臨界資源,都必須經過管程才能進入,而管程每次只允許一個進程進入管程,這樣實現進程互斥
- 管程的特性:
- 模塊化
- 是一個基本數據單位,可單獨編譯
- 抽象數據類型
- 管程中不僅有數據,還有對數據的操作
- 信息隱蔽
- 數據結構和過程的實現外部不可見
- 管程與進程區別
- 管程定義的是公用數據結構,而進程定義的是私有數據結構PCB
- 管程把共享變量上的同步操作集中起來,而臨界區卻分散在每個進程中
- 管程是為管理共享資源而建立的,進程主要是為占有系統資源和實現系統并發性而引入的
- 管程是被要使用共享資源的進程所調用的,管程和調用它的進程不能并發工作,而進程之間能并發工作,并發性是進程的固有特性
- 管程是OS中的一個資源管理模塊,供進程調用;而進程有生命周期:創建而產生,撤銷而消亡
- *條件變量 *
- 在管程機制中,當某個進程通過管程請求臨界資源未能滿足時,管程便調用wait原語使該進程等待,但等待的原因會有多個,通過在P,V操作前引入條件變量來說明作為區別
- 條件變量是一種抽象數據類型,每個條件變量保存了一個鏈表,用于記錄因該條件變量而堵塞的所有進程
- 條件變量的定義格式
- var x,y:condition;
- 對條件變量執行的兩種操作
- wait操作(如x.wait):用來堵塞正在調用管程的進程,并把進程塞入到與條件變量x對應的等待隊列,并釋放管程,直到x條件變化。此時其他進程可以使用該管程
- signal操作(如x.signal):用來喚醒與條件變量x對應的等待隊列中的一個進程(因為x條件而堵塞)。若沒有這樣的進程,則繼續執行原進程,不產生任何的結果
- 5.經典進程的同步問題
- 生產者-消費者問題
- 這個問題是最著名的進程同步問題。描述了一組生產者和一組消費者共享一個緩存池(有N個緩存池),生產者通過緩存池向消費者提供物品
- 定義兩個同步信號量
- empty : 代表緩存池中空緩存池的數量,初始為n
- full : 代表緩存池中滿緩存池的數量,初始為0
- 實際例子:
- M個生產者,K個消費者,公用N個緩存區的緩存池
- 設緩存池的長度為n(n>0),一群生產者進程P1,P2...Pm,一群消費者進程C1,C2...Ck,如果生產者和消費者是相互等效,只要緩存池未滿,生產者就可以把產品送入緩存區,類似地,只要緩存池為空,消費者便可以從緩存區取走產品并消耗他。生產者和消費者的同步關系將禁止生產者向滿的緩存池輸送產品,也禁止消費者從空的緩存池提取產品
- Snip20170111_2.png
- 設置兩個同步信號量和一個互斥信號量
empty:說明空緩沖區的數目,初值為緩存池數量n,代表有n個空緩沖區使用
full:說明滿緩存區的數量,即產品數量,初值為0,代表生產者尚未把產品放入緩存池,有0個滿緩存區可用
-
mutex:說明該緩存池是一臨界資源,必須互斥使用,初值為1
producer(){ while(true){ //生產一個產品放入nextp; P(empty); P(mutex); Buffer[in] = nextp; in = (in + 1) mod n; V(mutex); V(full); } } consumer(){ while(true){ P(full); P(mutex); nextc = Buffer[out]; out = (out + 1) mod n; V(mutex); v(empty); // 消費nextc中的產品 } }
- "生產者-消費者"問題中的注意事項
- 互斥信號量P、V操作在每一個進程中必須成對出現
- 對資源信號量(full,empty)的P、V操作也必須成對出現,但可以處于不同的程序中
- 多個P操作順序不能顛倒
- 先執行資源信號量的P操作,再執行互斥信號量P的操作,否則可能引起進程死鎖
- 這是一個同步問題:
- 消費者想要取產品,緩存區中至少有一個緩存池是滿的
- 生產者想要放產品,緩存池至少有一個緩存區是空的
- 這是一個互斥問題
- 緩存池是一個臨界資源,因此,各生產著進程和各消費者進程必須互斥訪問
- 使用管程機制解決"生產者-消費者"問題
- 建立Producer-consumer(PC)管程
- M個生產者,K個消費者,公用N個緩存區的緩存池
- 生產者-消費者問題
Monitor producerconsumer{
item buffer[N];
int in,out;
condition notfull,notempty;
int count;
public:
void put(item x){
if(count>=N)cwait(notfull);
buffer[in] = x;
in = (in + 1) % N;
count++;
csignal(notempty);
}
void get(item x){
if(count<=0) cwait(notempty);
x = buffer[out];
out = (out + 1) % N;
count--;
csignal(notfull);
}
{in=0;out=0;count=0;}
}PC;
- producer-consumer(PC)管程
- put(item)過程
- 生產者利用這個過程將產品放入到緩存池中,若緩存池滿(count n),則等待
- get(item)過程
- 消費者利用這個過程從緩存池中取出產品,若緩存池空(count 0),則等待
- cwait(condition)過程:對條件變量notfull和notempty進行操作,當管程被一個進程占用時,其他進程調用該過程時堵塞,并掛在條件condition的隊列上
- csignal(condition)過程:對條件變量notfull和notempty進行操作,喚醒在cwait執行后堵塞在條件condition隊列上的進程,如果這樣的進程不止一個,則選擇其中一個進程實施喚醒操作,若隊列為空,什么也不做
- 利用管程解決"生產者-消費者"問題時,其中的消費者和生產者可描述為:
void producer(){
item x;
while(TRUE){
...
producer an item in nextp;
PC.put(x);
}
}
void consumer(){
item x;
while(TRUE){
PC.get(x);
consumer the item in nextc;
...
}
}
void main(){
cobegin
producer();
consumer();
coend
}
- 哲學家進餐問題
- 描述:有五個哲學家,他們的生活方式是交替地進行思考和進餐。他們共用一張圓桌,分別坐在五張椅子上。在圓桌上有五個碗和五支筷子,平時一個哲學家進行思考,饑餓時便試圖取用其左、右最靠近他的筷子,只有在他拿到兩支筷子時才能進餐。進餐畢,放下筷子又繼續思考。
- 哲學家進餐問題可看作是并發進程并發執行時,處理共享資源的一個有代表性的問題。
- 使用記錄性信號量解決哲學家進餐問題
semphore chopstick[5] = {1,1,1,1,1}; // 分別表示5只筷子
philosopher(int i){
think;
P(chopstick[i];
P(chopstick[(i+1) mod 5]);
eat;
V(chopstick[i];
V(chopstick[(i+1) mod 5]);
}
// 如果五個哲學家同時eat,各自拿起了左邊的筷子,那么他們試圖去拿右邊的筷子時,因為已經沒有筷子了,就會陷入無期限等待,可能引起死鎖
// 解決死鎖
- 解決方法一:設置一個信號量Sm,其初值為4,用于限制同時進餐的哲學家數目至多為4,這樣第i個哲學家的活動描述為:
while(TRUE){
wait(Sm);
wait(chopstick[i]);
wait(chopstick[(i+1) mod 5]);
eat;
signal(chopstick[i]);
signal(chopstick[(i+1) mod 5]);
signal(Sm);
...
think;
}
- 解決方法二:對五個哲學家,規定:單號者進餐時,先拿左手(i)的筷子,再拿右手(i+1)的筷子。雙號相反。這樣即使五個人同時就餐,就不會產生死鎖
while(TRUE){
if odd(i){
wait(chopstick[i]);
wait(chopstick[(i+1) mod 5]);
}
else{
wait(chopstick[(i+1) mod 5]);
wait(chopstick[i]);
}
...
eat;
...
signal(chopstick[i]);
signal(chopstick[(i+1) mod 5]);
...
think;
...
}
- "讀者-作者"問題
- 描述
- 一個數據對象(數據文件或記錄)可被多個進程共享。其中,讀者(reader)進程要求讀,寫者(writer)進程要求寫或修改。
- 為了保證讀寫的正確性和數據對象的一致性,系統要求:當有讀者進程讀文件時,不允許任何寫者進程寫,但允許多個讀者同時讀;當有寫者進程寫時,不允許任何其它寫者進程寫,也不允許任何讀者進程讀。
- 問題的解決
- 該問題的同步算法描述
設置一個共享變量和兩個信號量
共享變量readcount:記錄當前正在讀數據集的讀進程數目,初值為0
讀互斥信號量rmutex:表示讀進程互斥的訪問共享變量readcount,初值為1
-
寫互斥信號量wmutex:表示寫進程與其他進程(讀、寫)互斥地訪問數據集,初值為1
semaphore rmutex = 1; semaphore wmutex = 1; int readcount = 0; main(){ cobegin reader(); write(); coend } reader(){ while(TRUE){ P(rmutex); if(readcount == 0) P(wmutex); readcount++; V(rmutex); // 讀數據集 P(rmutex); readcount--; if(readcount == 0) V(wmutex); // 第末位讀者允許寫者進 V(rmutex); } } write(){ while(TRUE){ P(wmutex);//阻止其他進程讀、寫 學數據集; V(wmutex);// 允許其他進程讀、寫 } }
- 該問題的同步算法描述
- 一個數據對象(數據文件或記錄)可被多個進程共享。其中,讀者(reader)進程要求讀,寫者(writer)進程要求寫或修改。
- 描述