進程管理git
程序的順序執行:僅當前一操做(程序段)執行完後,才能執行後續操做。程序員
程序順序執行時的特徵:順序性,封閉性,可再見性。github
前趨圖(Precedence Graph)是一個有向無循環圖,記爲DAG(Directed Acycilc Graph),用於描述進程之間執行的先後關係。圖中的每個節點可用於描述一個程序段或進程,乃至一條語句。結點間的有向邊則用於表示兩個結點之間存在的偏序(Partial Order)或前趨關係(Precedence Relation)「→」算法
→={(Pi, Pj)|Pi must complete before Pj may start}, 若是(Pi, Pj)∈→,可寫成Pi→Pj,稱Pi是Pj的直接前趨,而稱Pj是Pi的直接後繼。在前趨圖中,把沒有前趨的結點稱爲初始結點(Initial Node),把沒有後繼的結點稱爲終止結點(Final Node)數組
程序併發執行時的特徵安全
間斷性網絡
失去封閉性數據結構
不可再現性多線程
結構特徵:併發
動態性
併發性
獨立性
異步性
較典型的進程定義:
進程是程序的一次執行。
進程是一個程序及其數據在處理機上順序執行時所發生的活動。
進程是出如今一個數據集合上運行的過程,它是系統進行資源分配和調度的一個獨立單位。
就緒(Ready)狀態
執行狀態
阻塞狀態
引發掛起狀態的緣由:
終端用戶的請求;
父進程請求;
負責調節的需求;
操做系統的須要
進程狀態的轉換
活動就緒-->靜止就緒
活動阻塞-->靜止阻塞
靜止就緒-->活動就緒
靜止阻塞-->活動阻塞
具備掛起狀態的進程狀態圖
進程控制塊的做用:進程控制塊的做用是使一個在多道程序環境下不能獨立運行的程序(含數據),成爲一個能獨立運行的基本單位,一個能與其它進程併發執行的進程。
進程控制塊中的信息
進程標識符: 進程標識符用於唯一地標識一個進程。一個進程一般有兩種標識符:
內部標識符:在全部的操做系統中,都爲每個進程賦予一個唯一的數字標識符,它一般是一個進程的序號。 設置內部標識符主要是爲了方便系統使用
外部標識符:它由建立者提供,一般是由字母、數字組成,每每是由用戶(進程)在訪問該進程時使用。爲了描述進程的家族關係, 還應設置父進程標識及子進程標識。此外,還可設置用戶標識,以指示擁有該進程的用戶
處理機狀態:處理機狀態信息主要是由處理機的各類寄存器中的內容組成的。
進度調度信息:在PCB中還存放一些與進程調度和進程對換有關的信息,包括:
進程狀態,指明進程的當前狀態,做爲進程調度和對換時的依據
進程優先級,用於描述進程使用處理機的優先級別的一個整數,優先級別高的進程應優先得到處理機
進程調度所需的其它信息,它們與所採用的進程調度算法有關。
事件,是指進程由執行狀態轉變爲阻塞狀態所等待發生的事件,即阻塞緣由。
進程控制信息
程序和數據的地址,是指進程的程序和數據所在的內存或外存地(首)址,以便再調度到該進程執行時,能從PCB中找到其程序和數據
進程同步和通訊機制,指實現進程同步和進程通訊時必需的機制,如信息隊列指針、信號量等,他們可能所有或部分地放在PCB中
資源清單,是一張列出了除CPU之外的、進程所需的所有資源及已經分配到該進程的資源的清單。
連接指針,它給出了本進程(PCB)所在隊列中的下一個進程的PCB的首地址。
進程控制塊的組織方式
PCB鏈表隊列示意圖:
正在執行的進程,當發現上述某事件時,因爲沒法繼續執行,因而進程便經過調用阻塞原語block把本身阻塞。可見,進程的阻塞是進程自身的一種主動行爲。進入block過程後,因爲此時該進程還處於執行狀態,因此應先當即中止執行,把進程控制塊中的現行狀態由「執行」改成阻塞,並將PCB插入阻塞隊列。若是系統中設置了因不一樣事件而阻塞的多個阻塞隊列,則應將本進程插入到具備相同事件的阻塞(等待)隊列。 最後,轉調度程序進行從新調度,將處理機分配給另外一就緒進程,並進行切換,亦即,保留被阻塞進程的處理機狀態(在PCB中),再按新進程的PCB中的處理機狀態設置CPU的環境。
當被阻塞進程所期待的事件出現時,如I/O完成或其所期待的數據已經到達,則由有關進程(好比,用完並釋放了該I/O設備的進程)調用喚醒原語wakeup( ),將等待該事件的進程喚醒。
原語執行的過程是:首先把被阻塞的進程從等待該事件的阻塞隊列中移出,將其PCB中的現行狀態由阻塞改成就緒,而後再將該PCB插入到就緒隊列中
進程同步的主要任務是對多個相關進程在執行次序上進行協調,以使併發執行的諸進程之間能有效地共享資源和相互合做,從而使程序的執行具備可再現性。
臨界資源(Critical Resouce) 許多硬件資源如打印機、磁帶機等,都屬於臨界資源,諸進程間應採起互斥方式,實現對這種資源的共享。
生產者-消費者(producer-consumer)問題:有一羣生產者進程在生產產品,並將這些產品提供給消費者進程去消費。爲使生產者進程與消費者進程能併發執行,在二者之間設置了一個具備n個緩衝區的緩衝池,生產者進程將它所生產的產品放入一個緩衝區中; 消費者進程可從一個緩衝區中取走產品去消費。儘管全部的生產者進程和消費者進程都是以異步方式運行的,但它們之間必須保持同步,即不容許消費者進程到一個空緩衝區去取產品;也不容許生產者進程向一個已裝滿產品且還沒有被取走的緩衝區中投放產品。
咱們可利用一個數組來表示上述的具備n個(0,1,…,n-1)緩衝區的緩衝池。用輸入指針in來指示下一個可投放產品的緩衝區,每當生產者進程生產並投放一個產品後,輸入指針加1;用一個輸出指針out來指示下一個可從中獲取產品的緩衝區,每當消費者進程取走一個產品後,輸出指針加1。 因爲這裏的緩衝池是組織成循環緩衝的,故應把輸入指針加1表示成 in∶=(in+1)mod n;輸出指針加1表示成out∶=(out+1) mod n。當(in+1) mod n=out時表示緩衝池滿;而in=out則表示緩衝池空。此外,還引入了一個整型變量counter, 其初始值爲0。每當生產者進程向緩衝池中投放一個產品後,使counter加1;反之,每當消費者進程從中取走一個產品時, 使counter減1。生產者和消費者兩進程共享下面的變量:
Var n, integer; type item=…; var buffer:array[0, 1, …, n-1] of item; in, out: 0, 1, …, n-1; counter: 0, 1, …, n;
指針in和out初始化爲1。在生產者和消費者進程的描述中,no-op是一條空操做指令,while condition do no-op語句表示重複的測試條件(condication),重複測試應進行到該條件變爲false(假),即到該條件不成立時爲止。在生產者進程中使用一局部變量nextp,用於暫時存放每次剛生產出來的產品;而在消費者進程中,則使用一個局部變量nextc,用於存放每次要消費的產品。 producer: repeat ... produce an item in nextp; ... while counter=n do no-op; buffer[in]:=nextp; in:=(in+1)mod n; counter: =counter+1; until false; consumer: repeat while counter=0 do no-op; nextc: =buffer[out]; out: =(out+1) mod n; counter: =counter-1; consumer the item in nextc; until false;
雖然上面的生產者程序和消費者程序,在分別看時都是正確的,並且二者在順序執行時其結果也會是正確的,但若併發執行時,就會出現差錯,問題就在於這兩個進程共享變量counter。生產者對它作加1操做,消費者對它作減1操做,這兩個操做在用機器語言實現時, 常可用下面的形式描述:
register 1:=counter; register 2:=counter; register1:=register 1+1; register 2:=register 2-1; counter:=register 1; counter: =register 2;
假設:counter的當前值是5。若是生產者進程先執行左列的三條機器語言語句,而後消費者進程再執行右列的三條語句, 則最後共享變量counter的值仍爲5;反之,若是讓消費者進程先執行右列的三條語句,而後再讓 生產者進程執行左列的三條語句,counter值也仍是5,可是,若是按下述順序執行: register 1 :=counter; (register 1=5) register 1 :=register 1+1; (register 1=6) register 2 :=counter; (register 2=5) register 2 :=register 2-1; (register 2=4) counter :=register 1; (counter=6) counter :=register 2; (counter=4)
正確的counter值應該是5,可是如今是4.爲了預防產生這種錯誤,解決此問題的關鍵是應把變量counter做爲臨界資源處理,即,令生產者進程和消費者進程互斥地訪問變量counter。
同步機制應遵循的規則
最初由Dijkstra把整型信號量定義爲一個用於表示資源數目的整型量S,除初始化外,僅能經過兩個標準的原子操做(Atomic Operation) wait(S)和signal(S)來訪問。 這兩個操做被分別稱爲P、V操做。 wait和signal操做可描述爲:
wait(S): while S≤0 do no-op; S:=S-1; signal(S):S:=S+1;
在信號量機制中,除了須要一個用於表明資源數目的整型變量value外,還應增長一個進程鏈表L,用於連接等待進程。記錄型信號量是因爲它採用了記錄型的數據結構而得名的。它所包含的上述兩個數據項可描述爲:
type semaphore=record value:integer; L:list of process; end
相應地,wait(S)和signal(S)操做可描述爲:
procedure wait(S) var S: semaphore; begin S.value∶ =S.value-1; if S.value<0 then block(S,L) end procedure signal(S) var S: semaphore; begin S.value∶ =S.value+1; if S.value≤0 then wakeup(S,L); end
在記錄型信號量機制中,S.value的初值表示系統中某類資源的數目, 於是又稱爲資源信號量,對它的每次wait操做,意味着進程請求一個單位的該類資源,所以描述爲S.value∶ =S.value-1; 當S.value<0時,表示該類資源已分配完畢,所以進程應調用block原語,進行自我阻塞,放棄處理機,並插入到信號量鏈表S.L中。可見,該機制遵循了「讓權等待」準則。 此時S.value的絕對值表示在該信號量鏈表中已阻塞進程的數目。 對信號量的每次signal操做,表示執行進程釋放一個單位資源,故S.value∶ =S.value+1操做表示資源數目加1。 若加1後還是S.value≤0,則表示在該信號量鏈表中,仍有等待該資源的進程被阻塞,故還應調用wakeup原語,將S.L鏈表中的第一個等待進程喚醒。若是S.value的初值爲1,表示只容許一個進程訪問臨界資源,此時的信號量轉化爲互斥信號量。
AND同步機制的基本思想是:將進程在整個運行過程當中須要的全部資源,一次性所有地分配給進程,待進程使用完後再一塊兒釋放。只要尚有一個資源未能分配給進程,其它全部可能爲之分配的資源,也不分配給他。亦即,對若干個臨界資源的分配,採起原子操做方式:要麼所有分配到進程,要麼一個也不分配。 由死鎖理論可知,這樣就可避免上述死鎖狀況的發生。爲此,在wait操做中,增長了一個「AND」條件,故稱爲AND同步,或稱爲同時wait操做, 即Swait(Simultaneous wait)定義以下:
Swait(S1, S2, …, Sn) if Si≥1 and … and Sn≥1 then for i∶ =1 to n do Si∶=Si-1; endfor else place the process in the waiting queue associated with the first Si found with Si<1, and set the program count of this process to the beginning of Swait operation endif Ssignal(S1, S2, …, Sn) for i∶ =1 to n do Si=Si+1; Remove all the process waiting in the queue associated with Si into the ready queue. endfor;
通常「信號量集」的幾種特殊狀況: (1) Swait(S, d, d)。 此時在信號量集中只有一個信號量S, 但容許它每次申請d個資源,當現有資源數少於d時,不予分配。 (2) Swait(S, 1, 1)。 此時的信號量集已蛻化爲通常的記錄型信號量(S>1時)或互斥信號量(S=1時)。 (3) Swait(S, 1, 0)。這是一種很特殊且頗有用的信號量操做。當S≥1時,容許多個進程進入某特定區;當S變爲0後,將阻止任何進程進入特定區。換言之,它至關於一個可控開關。
管程(Monitors):一種新的進程同步工具 1. 管程的定義 管程由四部分組成: - 管程的名稱、 - 局部於管程內部的分享數據結構說明、 - 對該數據進行操做的一組過程、 - 對局部於管程內部的共享數據設置初始值的語句。
管程至關於圍牆,它把共享變量和對它進行操做的若干過程圍了起來,全部進程要訪問臨界資源時,都必須通過管程(至關於經過圍牆的門)才能進入,而管程每次只准許一個進程進入管程,從而實現了進程互斥。 管程的特性:
2.條件變量 考慮一種狀況:當一個進程調用了管程,在管程中時被阻塞或掛起,直到阻塞或掛起的緣由解除,而在此期間,若是該進程不釋放管程,則其餘進程沒法進入管程,被迫長時間地等待。爲了解決這個問題,引入了條件變量condition。對這些條件變量的訪問,只能在管程中進行。 管程中對每個條件變量都需予以說明,其形式爲:Var x,y:condition。對條件變量的操做僅僅是wait和signal,所以條件變量也是一種抽象數據類型,每一個條件變量保存了一個鏈表,用來記錄因該條件變量而阻塞的全部進程,同時提供的兩個操做便可表示爲x.wait和x.signal。其含義爲
信號量機制做爲同步工具是卓有成效的,但做爲通訊工具,則不夠理想,主要表如今兩個方面:
本節所介紹的是高級進程通訊,是指用戶可直接利用操做系統所提供的一組通訊命令高效地傳送大量數據的一種通訊方式。操做系 統隱藏了進程通訊的實現細節。即通訊過程對用戶是透明的,這樣就大大減小了通訊程序編制上的複雜性。
目前,高級通訊機制可歸結爲三大類:共享存儲器系統、消息傳遞系統以及管道通訊系統。 1. 共享存儲器系統 在共享存儲器系統(Shared-Memory System)中,相互通訊的進程共享某些數據結構或共享數據存儲區,進程之間可以經過這些空間進行通訊。 1. 基於共享數據結構的通訊方式。 在這種通訊方式中,要求諸進程公用某些數據結構,藉以實現諸進程間的信息交換。這種通訊方式是低效的,只適於傳遞相對少許的數據。 2. 基於共享存儲區的通訊方式 爲了傳輸大量數據、在存儲器中劃出了一塊共享存儲區,諸進程可經過對共享存儲區中數據的讀或寫來實現通訊。進程在通訊前,先向系統申請得到共享存儲區中的一個分區,並指定該分區的關鍵字;若系統已經給其餘進程分配了這樣的分區,則將該分區的描述符返回給申請者,繼之,由申請者把得到的共享存儲區鏈接到本進程中;此後,即可像讀、寫普通存儲器同樣地讀、寫該公用存儲分區。 2. 消息傳遞系統 消息傳遞系統(Message passing system)是當前應用最普遍的一種進程間的通訊機制。在該機制中,進程間的數據交換是以格式化的消息(message)爲單位的;在計算機網絡中又把message稱爲報文。程序員直接利用操做系統提供的一組通訊命令(原語),不只能實現大量數據的傳遞,並且還隱藏了通訊的實現細節,是通訊過程對用戶是透明的,從而大大減化了通訊程序編制的複雜性。 3. 管道通訊 所謂"管道",是指用於鏈接一個讀進程和一個寫進程以實現它們之間通訊的一個共享文件,又名pipe文件。向管道(共享文件)提供輸入
在OS中的每個線程均可以利用線程標識符和一組狀態參數進行描述。狀態參數一般有這樣幾項:
線程在運行時,具備三種基本狀態:
在多線程OS環境下,應用程序在啓動時,一般僅有一個線程在執行,該線程被人們稱爲「初始化線程」。它可根據須要再去建立若干個線程。在建立新線程時,須要利用一個線程建立函數(或系統調用),並提供相應的參數,如指向線程主程序的入口指針、堆棧的大小,以及用於調度的優先級等。在線程建立函數執行完後,將返回一個線程標識符供之後使用。 終止線程的方式有兩種:一種是在線程完成了本身的工做後自願退出;另外一種是線程在運行中出現錯誤或因爲某種緣由而被其它線程強行終止。
在多線程OS中,進程是做爲擁有系統資源的基本單位,一般的進程都包含多個線程併爲它們提供資源,但此時的進程就再也不做爲一個執行的實體。 多線程OS中的進程有如下屬性: 1. 做爲系統資源分配的單位 2. 可包括多個線程 3. 進程不是一個可執行的實體
內核支持線程 這裏所謂的內核支持線程,也都一樣是在內核的支持下運行的,即不管是用戶進程中的線程,仍是系統進程中的線程,他們的建立、撤消和切換等,也是依靠內核實現的。此外,在內核空間還爲每個內核支持線程設置了一個線程控制塊, 內核是根據該控制塊而感知某線程的存在的,並對其加以控制。
用戶級線程 用戶級線程僅存在於用戶空間中。對於這種線程的建立、 撤消、線程之間的同步與通訊等功能,都無須利用系統調用來實現。對於用戶級線程的切換,一般是發生在一個應用進程的諸多線程之間,這時,也一樣無須內核的支持。因爲切換的規則遠比進程調度和切換的規則簡單,於是使線程的切換速度特別快。可見,這種線程是與內核無關的。