一.進程(最開始的信息,在引入線程之后會有變化)
定義:
程序: 就是一個指令序列
進程:就是程序的一次執行過程(動態性)。它是系統進行資源和調度的一個獨立單位。
程序段、數據段、PCB三部分組成了進程實體(進程映像)。一般情況下,我們把進程實體就簡稱為進程,例如,所謂創建進程,實質上是創建進程實體中的PCB;
而撤銷進程,實質上是撤銷進程實體中的PCB。注意:PCB是進程存在的唯一標志!
進程的組成:
PCB是進程存在的唯一標志
進程描述信息
1、PCB: 進程控制和管理信息(進程的管理者(操作系統)所需要的數據都在PCB)
資源分配清單
處理相關信息
2、程序段: 存放要執行的代碼(程序本身的運行所需要的數據在程序段、數據段中)
3、數據段: 存放程序運行過程中處理的各種數據。
進程的組織形式:
1、鏈式方式:按進程狀態將PCB分為多個隊列,操作系統持有指向各個隊列的指針
2、索引方式:按照進程狀態建立幾張索引表,各表項指向一個PCB
進程的特征:
1、動態性 (進程的基本特征):進程與程序的區別在於,程序只是一個靜態的指令集合,而進程是一個正在系統中活動的指令集合。在進程中加入了時間的概念。進 程具有自己的生命周期和各種不同的狀態,在程序中是沒有這些概念的。進程是程序的一次執行過程,是動態地產生、變化和消亡的
2、並發性:並行指在同一時刻有多條指令在多個處理器上同時執行;
並發才旨在同一時刻只能有一條指令執行,但多個進程指令被快速輪換執行,使得在宏觀上具有多個進程同時執行的效果。大部分操作系統都支持多進程並發 執行,現代的操作系統幾乎都支持同時執行多個任務。
3、 獨立性:進程是系統中獨立存在的實體,它可以擁有自己的獨立的資源,每一個進程都擁有自己的私有的地址空間。在沒有經過進程本身允許的情況下,一個 用戶進程不可以直接訪問其他進程的地址空間。是資源分配、接受調度的基本單位。
4、異步性:是指進程是按異步方式運行的,即按各自獨立的、不可預知的速度向前推進。正是淤於此因,才導致了傳統意義上的程序若參與並發執行,會產生其 結果的不可再現性。為使進程在並發運行時雖具有異步性,但仍能保證進程並發執行的結果是可冉現的,在OS中引進了進程的概念,並且配置相應的進程同步 機制。‘’進程同步機制‘’
5、結構性:每一個進程都會配置一個PCB。結構上看,進程由程序段、數據段、PCB組成。
進程的狀態與轉換:
三種基本狀態
1、運行狀態(Runing):占有CPU,並在CPU上運行。CPU ✔,所需其他資源 ✔。
注意:單核處理機環境下,每一時刻最多只有一個進程處於運行態。(雙核環境下可以同時有兩個進程處於運行態)
2、就緒狀態(Ready):已經具備運行條件,但由於沒有空閑CPU,而暫時不能運行。CPU ✘,所需其他資源 ✔。
進程已經擁有了除處理機之外所有需要的資源,一旦獲得處理機,即可立即進入運行態開始運行。
即:萬事俱備,只欠CPU
3、阻塞狀態(Waiting/Blocked,又稱:等待態):因等待某一件事情而暫時不能運行。CPU ✘,所需其他資源 ✘。
如:等待操作系統分配打印機、等待讀磁盤操作的結果。CPU是計算機中最昂貴的部件,為了提高CPU的利用率,需要先將其他進程需要的資源分配到位,才能 得到CPU的服務
另外兩種狀態
1、創建狀態(New,又稱:新建態):進程正在被創建,操作系統為進程分配資源、初始化PCB
2、終止狀態(Terminated,又稱:結束態):進程運行結束(或者由於bug導致進程無法繼續執行下去,比如數組越界錯誤),需要撤銷進程。
操作系統需要完成撤銷進程相關的工作。完成將分配給進程的資源回收,撤銷進程PCB等工作。
進程狀態間的轉換
1、就緒態—>運行態 :進程被調度
2、運行態—>就緒態 :時間片到,或CPU被其他高優先級的進程搶占
3、運行態—>阻塞態 :等待系統資源分配,或等待某件事發生(主動行為)
4、阻塞態—>就緒態 :資源分配到位,等待某件事發生(被動行為)
5、創建態—>就緒態 :系統完成創建進程相關的工作
6、運行態—>終止態 :進程運行結束,或運行過程中遇到不可修復的錯誤
進程狀態間的轉換圖
進程控制
基本概念
進程控制的主要功能是對系統中的所有進程實施有效的管理,它具有創建新進程、撤銷已有進程、實現進程狀態轉換等功能。
簡化理解:反正進程控制就是要實現進程狀態轉換
用原語實現進程控制。原語的特點是執行期間不允許中斷,只能一氣呵成。
這種不可被中斷的操作即原子操作。
原語采用“關中斷指令”和“開中斷指令”實現 。
原語是一種特殊程序。
用於:
進程的終止
撤消原語(就緒態/阻塞態/運行態→終止態>無)
1、從PCB集合中找到終止進程的PCB
2、若進程正在運行,立即剝奪CPU,將CPU分配給其他進程
3、終止其所有子進程
4、將該進程擁有的所有資源歸還給父進程或操作系統
5、刪除PCB
引發進程終止的事件
1、正常結束
2、異常結束
3、外界干預
進程的阻塞和喚醒(阻塞原語和喚醒原語必須成對使用)
進程的阻塞
阻塞原語(運行態—>阻塞態):
1、找到要阻塞的進程對應的PCB
2、保護進程運行現場,將PCB狀態信息設置為”阻塞態“,暫時停止進程運行
3、將PCB插入相應事件的等待序列
引起阻塞的事件:
1、需要等待系統分配某種資源
2、需要等待相互合作的其它進程完成工作
進程的喚醒
喚醒原語(阻塞態—>就緒態):
1、在事件等待序列中找到PCB
2、將PCB從等待序列移除,設置進程為就緒態
3、將PCB插入就緒隊列,等待被調度。
引起進程喚醒的事件:
1、等待事件發生(注意:因何事阻塞就應何事喚醒)
進程的切換
切換原語(運行態—>阻塞態/就緒態,就緒態—>運行態)
1、將運行環境信息存入PCB
2、PCB移入相應的隊列
3、選擇另一個進程執行,並更新其PCB
4、根據PCB恢復新進程所需要的運行的環境
引起進程切換的事件
1、當前進程時間片到
2、有更高優先級的進程到達
3、當前進程主動阻塞
4、當前進程終止
進程通信:
定義:
顧名思義,進程通信就是指進程之間的信息交換。進程是分配系統資源的單位(包括內存地址空間),因此各進程擁有的內存地址空間相互獨立。
為了保證安全,一個進程不能直接訪問另一個進程的地址空間。
但是進程之間的信息交換又是必須實現的。為了保證進程間的安全通信,操作系統提供了一些方法。
共享存儲
兩個進程對共享空間的訪問必須是互斥的(互斥訪問通過操作系統提供的工具實現)。操作系統只負責提供共享空間和同步互斥工具(如P、V操作)。
設置一個共享空間,要互斥的訪問共享空間。
兩種方式:
基於數據結構的共享:比如共享空間里只能放一個長度為10的數組。這種共享方式速度慢、限制多,是一種低級通信方式
基於存儲區的共享:在內存中畫出一塊共享存儲區,數據的形式、存放位置都由進程控制,而不是操作系統。相比之下,這種共享方式速度更快,
是一種高級通信方式。
消息傳遞
進程間的數據交換以格式化的消息(Message)為單位。進程通過操作系統提供的“發送消息/接收消息”兩個原語進行數據交換。
傳遞結構化的信息(消息頭/消息體)
系統提供”發送/接受原語“
直接通信方式 :消息直接掛到接受進程的消息緩沖隊列上
間接通信方式 :消息要先發送到中間實體(信箱)中,因此也稱 “信箱通信方式” ,Eg:計網中的電子郵件系統。
管道通信
1、管道只能采用半雙工通信,某一時間段內只能實現單向的傳輸。如果要實現雙向同時通信,則需要設置兩個管道。
2、各進程要互斥地訪問管道。
3、數據以字符流的形式寫入管道,當管道寫滿時,寫進程的write()系統調用將被阻塞,等待讀進程將數據取走。當讀進程將數據全部取走后,管道變空,
此時讀進程 的read()系統調用將被阻塞。
4、如果沒寫滿,就不允許讀。如果沒讀空,就不允許寫。
5.、數據一旦被讀出,就從管道中被拋棄,這就意味着讀進程最多只能有一個,否則可能會有讀錯數據的情況。
二、線程概念多線程模型。
線程:
1、可以把線程理解為“輕量級進程”
2、線程是一個基本的CPU執行單元,也是程序執行流的最小單位。引入線程之后,不僅是進程之間可以並發,進程內的各線程之間也可以並發,
從而進一步提升了系統的並發度,使得一個進程內也可以並發處理各種任務(如QQ視頻、文字聊天、傳文件)
3、引入線程后,進程只作為除CPU之外的系統資源的分配單元(如打印機、內存地址空間等都是分配給進程的)
4、線程則作為處理機的分配單元。
引入線程的變化:
1、資源分配、調度:
傳統進程機制中,進程時資源分配,調度的基本單位
引入線程后,進程是資源分配的基本單位,線程是調度的基本單位
2、並發性:
傳統進程機制中,只能進程間並發
引入線程后,各線程間也能並發,提升了並發性
3、系統開銷:
傳統的進程間並發,需要切換進程的運行環境,系統開銷很大
線程間並發,如果是同一進程內的線程切換運行,則不需要切換進程環境,系統開銷小
引入線程后,並發所帶來的系統開銷小
4、類比:
去圖書館看書。切換進程運行環境:有一個不認識的人要用桌子,你需要你的書收走,他把自己的書放到桌上同一進程內的線程切換=你的舍友要用這張書桌,
可以不把桌子上的書收走
線程的屬性:
1、線程是處理機調度的單位。
2、多CPU計算機中,各個線程可占用不同的CPU。
3、每個線程都有一個ID、線程控制塊(TCB)。
4、線程也有就緒、阻塞、運行三種基本狀態。
5、線程幾乎不擁有系統資源。同一進程的不同線程間共享進程的資源。
6、由於共享內存地址空間,同一進程中的線程間通信甚至無需系統干預。
7、同一進程中的線程切換,不會引起進程切換。不同進程中的線程切換,會引起進程切換。切換同進程內的線程,系統開銷很小。切換進程,系統開銷較大。
線程實現方式:
用戶級線程(User-Level Thread, ULT)
用戶級線程由應用程序通過線程庫實現。所有的線程管理工作都由應用程序負責(包括線程切換)
用戶級線程中,線程切換可以在用戶態下即可完成,無需操作系統干預。
在用戶看來,是有多個線程。但是在操作系統內核看來,並意識不到線程的存在。(用戶級線程對用戶不透明,對操作系統透明)
可以這樣理解,“用戶級線程”就是“從用戶視角看能看到的線程”
內核級線程(Kernel-Level Thread,KLT,又稱“內核支持的線程”)
內核級線程的管理工作由操作系統內核完成。線程調度、切換等工作都由內核負責,因此內核級線程的切換必然需要在核心態下才能完成。
可以這樣理解,“內核級線程”就是“從操作系統內核視角看能看到的線程”
在同時支持用戶級線程和內核級線程的系統中,可采用二者組合的方式:將n個用戶級線程映射到m個內核級線程上 ( n >= m)
重點重點重點:
操作系統只“看得見”內核級線程,因此只有內核級線程才是處理機分配的單位。
例如:左邊這個模型中,該進程由兩個內核級線程,三個用戶級線程,在用戶看來,這個進程中有三個線程。但即使該進程在一個4核處理機的計算機上運行,也最多只能被分配到兩個核,最多只能有兩個用戶線程並行執行。
多線程模型
多對一模型
多對一模型:多個用戶及線程映射到一個內核級線程。每個用戶進程只對應一個內核級線程。
優點:用戶級線程的切換在用戶空間即可完成,不需要切換到核心態,線程管理的系統開銷小,效率高。
缺點:當一個用戶級線程被阻塞后,整個進程都會被阻塞,並發度不高。多個線程不可在多核處理機上並行運行。
一對一模型
一對一模型:一個用戶及線程映射到一個內核級線程。每個用戶進程有與用戶級線程同數量的內核級線程。
優點:當一個線程被阻塞后,別的線程還可以繼續執行,並發能力強。多線程可在多核處理機上並行執行。
缺點:一個用戶進程會占用多個內核級線程,線程切換由操作系統內核完成,需要切換到核心態,因此線程管理的成本高,開銷大。
多對多模型
多對多模型: n用戶及線程映射到m個內核級線程(n >= m)。每個用戶進程對應m個內核級線程。
克服了多對一模型並發度不高的缺點,又克服了一對一模型中一個用戶進程占用太多內核級線程,開銷太大的缺點。
進程同步、進程互斥
進程同步
知識點回顧:進程具有異步性的特征。異步性是指,各並發執行的進程以各自獨立的、不可預知的速度向前推進。
並發性帶來了異步性,有時需要通過進程同步解決這種異步問題。
有的進程之間需要相互配合地完成工作,各進程的工作推進需要遵循一定的先后順序。
進程通信――管道通信
讀進程和寫進程並發地運行,由於並發必然導致異步性,因此“寫數據”和“讀數據”兩個操作執行的先后順序是不確定的。而實際應用中,又必須按照“寫數據→讀數據”的順序來執行的。如何解決這種異步問題,就是“進程同步”所討論的內容。
同步亦稱直接制約關系,它是指為完成某種任務而建立的兩個或多個進程,這些進程因為需要在某些位置上協調它們的工作次序而產生的制約關系。進程間的直接制約關系就是源於它們之間的相互合作。
同時共享方式
系統中的某些資源,允許一個時間段內由多個進程 “同時” 對它們進行訪問資源。
進程互斥:
進程的“並發”需要“共享”的支持。各個並發執行的進程不可避免的需要共享一些系統資源(比如內存,又比如打印機、攝像頭這樣的I/O設備)
互斥共享方式
系統中的某些資源,雖然可以提供給多個進程使用,但一個時間段內只允許一個進程訪問資源。
我們把一個時間段內只允許一個進程使用的資源稱為臨界資源。許多物理設備(比如攝像頭、打印機)都屬於臨界資源。
此外還有許多變量、數據、內存緩沖區等都屬於臨界資源。
對臨界資源的訪問,必須互斥地進行。互斥,亦稱間接制約關系。進程互斥指當一個進程訪問某臨界資源時,另一個想要訪問該臨界資源的進程必須等待。
當前訪問臨界資源的進程訪問結束,釋放該資源之后,另一個進程才能去訪問臨界資源。
對臨界資源的訪問,需要互斥的進行。即同一時間段內只能允許一個進程訪問該資源。
四個部分:
1、進入區:檢查是否可進入臨界區,若可進入,需要 “上鎖”
2、臨界區:訪問臨界資源的那段代碼
3、退出區:負責 “解鎖”
4、剩余區:其余代碼部分
需要遵循的原則:
1、空閑讓進:臨界區空閑時,可以允許一個請求進入臨界區的進程立即進入臨界區。
2、忙則等待:當已有進程進入臨界區時,其他試圖進入臨界區的進程必須等待。
3、有限等待:對請求訪問的進程,應保證能在有限時間內進入臨界區(保證不會飢餓)。
4、讓權等待:當進程不能進入臨界區時,應立即釋放處理機,防止進程忙等待。
注意:臨界區是進程中訪問臨界資源的代碼段。進入區和退出區是負責實現互斥的代碼段。臨界區也可稱為“臨界段”。
進程互斥的軟件實現方法:
單標志法:
1、在進入區只做 “檢查”,不 “上鎖”
2、在退出區把臨界區的使用權轉交給另一個進程(相當於在退出區既給另一個進程 “ 上鎖”,又給自己 “上鎖”)
3、主要問題:不遵循 “空閑讓進” 原則
雙標志先檢查:
1、在進入區先 “檢查” 后 “上鎖”,退出區 “解鎖”
2、主要問題:不遵循 “忙則等待” 原則
雙標志后檢查:
1、在進入區先 “加鎖” 后 “檢查”,退出區 “解鎖”
2、主要問題:不遵循 “空閑讓進,有限等待” 原則,可能導致 ”飢餓“
Peterson算法:
1、在進入區 ”主動爭取 — 主動謙讓 — 檢查對方是否想進、己方是否謙讓“
2、主要問題:不遵循 ”讓權等待“ 原則,會發生 ”忙等“
進程互斥的硬件實現方法:
中斷屏蔽方法:
使用 ”開/關中斷“指令實現,有點:簡單高效。缺點:只適用於單處理機;只適用於操作系統內核進程
TestAndSet(TS指令/TSL指令):
old記錄是否已被上鎖;再將look設置為true;檢查臨界區是否已被上鎖(若已上鎖,則循環重復前幾步)
優點:實現簡單;適用於多處理機環境;
缺點:不滿足”讓全等待“
Swap指令(XCHG指令):邏輯同上TSL。
信號量機制
整型信號量
記錄型信號量
復習回顧+思考:之前學習的這些進程互斥的解決方案分別存在哪些問題?
進程互斥的四種軟件實現方式(單標志法、雙標志先檢查、雙標志后檢查、Peterson算法)進程互斥的三種硬件實現方式(中斷屏蔽方法、TS/TSL指令、Swap/XCHG指令)
1.在雙標志先檢查法中,進入區的“檢查”、“上鎖”操作無法一氣呵成,從而導致了兩個進程有可能同時進入臨界區的問題;
2.所有的解決方案都無法實現“讓權等待”
1965年,荷蘭學者Dijikstra提出了一種卓有成效的實現進程互斥、同步的方法――信號量機制。
信號機制:
用戶進程可以通過使用操作系統提供的一對原語來對信號量進行操作,從而很方便的實現了進程互斥、進程同步。
信號量其實就是一個變量(可以是一個整數,也可以是更復雜的記錄型變量),可以用一個信號量來表示系統中某種資源的數量,比如:系統中只有一台打印機,
就可以設置一個初值為1的信號量。
原語是一種特殊的程序段,其執行只能一氣呵成,不可被中斷。原語是由關中斷/開中斷指令實現的。軟件解決方案的主要問題是由“進入區的各種操作無法一氣呵成”,
因此如果能把進入區、退出區的操作都用“原語”實現,使這些操作能“一氣呵成”就能避免問題。
一對原語: wait(S)原語和signal(S)原語,可以把原語理解為我們自己寫的函數,函數名分別為 wait和signal,括號里的信號量S其實就是函數調用時傳入的一個參數。
wait、signal原語常簡稱為P、V操作(來自荷蘭語 proberen和 verhogen)。因此,做題的時候常把wait(S)、signal(S)兩個操作分別寫為P(S)、V(S)
整型信號量
1、用一個整數型變量作為信號量,數值表示某種資源數
2、整型信號量與普通整型變量的區別:對信號量只能執行初始化、P、V三種操作
3、整型信號量存在的問題:不滿足讓權等待原則
記錄型信號量
1、S.value表示某種資源數,S.L指向等待該資源的隊列
2、Р操作中,一定是先S.value--,之后可能需要執行block 原語
3、V操作中,一定是先S.value++,之后可能需要執行wakeup 原語
4、注意:要能夠自己推斷在什么條件下需要執行block 或 wakeup
5、可以用記錄型信號量實現系統資源的“申請"和“釋放”
6、可以用記錄型信號量實現進程互斥、進程同步
wait(S)、signal(S)也可以記為P(S)、v(S),這對原語可用於實現系統資源的“申請”和“釋放”。
S.value的初值表示系統中某種資源的數目。
對信號量s的一次Р操作意味着進程請求一個單位的該類資源,因此需要執行S.value--,表示資源數減1,當S.value <0時表示該類資源已分配完畢,
因此進程應調用block原語進行自我阻塞(當前運行的進程從運行態→阻塞態),主動放棄處理機,並插入該類資源的等待隊列S.L中。
可見,該機制遵循了“讓權等待”原則,不會出現“忙等”現象。
對信號量s的一次V操作意味着進程釋放一個單位的該類資源,因此需要執行S.value++,表示資源數加1,若加1后仍是S.value <=o,
表示依然有進程在等待該類資源,因此應調用wakeup 原語喚醒等待隊列中的第一個進程(被喚醒進程從阻塞態→就緒態)。
用信號量實現進程互斥、同步、前驅關系
除了互斥、同步問題外,還會考察有多個資源的問題,有多少資源就把信號量初值設為多少。申請資源時進行P操作,釋放資源時進行V操作即可。
實現進程互斥:
1、分析問題,確定臨界區
2、設置互斥信號量,初始值為1(互斥問題,信號量初值為1)
3、臨界區之前對信號量執行P操作
4、臨界區之后對信號量執行V操作
實現進程同步:
1、分析問題,找出哪里需要 ”一前一后“ 的同步關系
2、設置同步信號量,初始值為0(同步問題,信號量初始值為0)
3、在 ”前操作“ 之后執行V操作
4、在 ”后操作“ 之前執行P操作
實現進程的前驅關系:
1、分析問題,畫出前驅圖,把每一對前驅關系都看成一個同步問題(前驅關系問題,本質上就是更復雜的同步問題)。
2、為每一對前驅關系設置同步信號量,初值為0
3、在每個 ”前操作“ 之后執行V操作
4、在每個 ”后操作“ 之前執行P操作
生產者消費者問題
系統中有一組生產者進程和一組消費者進程,生產者進程每次生產一個產品放入緩沖區,消費者進程每次從緩沖區中取出一個產品並使用。
(注:這里的“產品”理解為某種數據)
生產者、消費者共享一個初始為空、大小為n的緩沖區。
只有緩沖區沒滿時,生產者才能把產品放入緩沖區,否則必須等待。
只有緩沖區不空時,消費者才能從中取出產品,否則必須等待。
緩沖區是臨界資源,各進程必須互斥地訪問。