談談操作系統的多進程


操作系統的多進程圖像

操作系統主要控制計算機的硬件,而其中最重要的就是CPU,因此操作系統的最主要工作就是控制CPU更好地執行命令,那么在介紹進程之前,我們首先來了解一下CPU的工作原理是怎樣的。

一、CPU的工作模式

首先,CPU取出程序指針PC,然后到對應的寄存器中取出地址為PC的指令,通過譯碼來分析指令的內容,移動相應寄存器的內容來實現指令,最后程序指針PC指向下一條指令,CPU重復上述工作過程。總的來說,CPU的工作模式就是 “取址-譯碼-執行”。比如CPU執行如下所示的指令:

50: mov ax, [100]
51: mov bx, [101]
52: add ax, bx
......
100: 1
101: 2

首先,PC 指針被設置為 50,CPU取出指令 mov ax, [100] 執行,將內存地址為 100 中的數據移動到寄存器 ax 中。當 50 中的指令完成后,PC指針指向 51,CPU執行 mov bx, [101],最后 PC 指向 52,將 axbx 的數據相加,此時 ax=3

這種工作模式在只能等待某一段程序執行完成之后才能執行另外一段,那么當正在執行的程序卡在某一條指令時(比如讀取磁盤上的數據,調用IO等),CPU就會停在這里等待該指令完成,因此CPU的利用率很低。

二、多道程序系統

多道程序系統是在計算機內存中同時存放幾道相互獨立的程序,使它們在管理程序控制之下,相互穿插的運行 (系統由一個程序轉而運行另一個程序時需要使用中斷機構中斷正在運行的程序) ,以使系統中的各種資源盡可能地滿負荷工作,從而提高整個計算機系統的使用效率。 兩個或兩個以上程序在計算機系統中同處於開始和結束之間的狀態,這就稱為多道程序系統。其技術運行的特征:多道、宏觀上並行、微觀上串行。如下圖所示:

如上圖所示:

  1. 單道程序的 CPU 和 DEV 的執行效率為:\(CPU = (10+5+10+10+5)/80 = 0.5, DEV = (5+10+10+5+10)/80 = 0.5\)
  2. 多道程序的 CPU 和 DEV 的執行效率為:\(CPU = (10+10+5+5+10)/45 = 0.89, DEV = (10+5+5+10+10)/45 = 0.89\)

因此,多道程序系統能夠顯著提高 CPU 和 DEV 的利用率。在程序運行的時候,每個程序都需要 PC 以及各種寄存器來描述程序的運行狀態,那么這些運行着的程序就叫做進程。通過上述分析,我們可以將進程的特征總結如下:

  1. 動態性:進程是程序的一次執行,它有着創建、活動、暫停、終止等過程,具有一定的生命周期,是動態地產生、變化和消亡的。動態性是進程最基本的特征。
  2. 並發性:指多個進程實體同時存於內存中,能在一段時間內同時運行。並發性是進程的重要特征,同時也是操作系統的重要特征。引入進程的目的就是為了使程序能與其他進程的程序並發執行,以提高資源利用率。
  3. 獨立性:指進程實體是一個能獨立運行、獨立獲得資源和獨立接受調度的基本單元。凡未建立PCB的程序都不能作為一個獨立的單元參與運行。
  4. 異步性:由於進程的相互制約,使得進程具有執行的間斷性,即進程按各自獨立的、不可預知的速度向前推進。異步性會導致執行結果的不可再現性,為此在操作系統中必須配置相應的進程同步機制。
  5. 結構性:每個進程都配置一個PCB對其進行描述。從結構上看,進程實體是由程序段、數據段和進程控制塊三部分組成的。

三、多進程圖像

3.1進程的狀態轉換

根據進程的運行狀態,可以把進程簡單地分為新建態,就緒態,運行態,阻塞態和終止態五種狀態。比如,你去食堂打飯,那么排隊的人組成了一個隊列,1)每個處在隊列的人的狀態就是就緒態;2)同一時刻窗口只能處理一個人的請求,因此正在處理的那個人被稱為運行態;3)但是當准備打飯的時候忘了帶飯卡,這個人就從運行態變為阻塞態,直到取回飯卡又變成就緒態。進程之間的狀態轉換如下圖所示:

3.2 進程的切換

在同一時刻,內存中存在多個進程,可以根據用戶的操作而進行切換。那么進程切換的具體過程是怎樣的呢?如下圖所示,假設內存中有兩個進程,在進程1執行過程中切換到進程2 ,此時:1)記錄下進程1中的PC指針,否則無法切換回來; 2)將PC指針切換為進程2的程序開始為止,開始執行進程2。

但是,由於在執行進程2的過程中,更改了寄存器 ax, bx 的值,因此再次切回到進程1時,52號命令 'add ax, bx' 執行完畢后 ax 中的值為 50,而非 1。因此在進程切換時,除了要記錄下程序指針 PC 之外,還要記錄一些與進程1 密切相關的寄存器的值,這個存放信息的結構被稱為進程控制塊(Progress Control Block, PCB)。當再次切換回來時,首先加載進程1 的PCB中的數據,然后執行相應的指令。因此,根據上述分析,進程之間的切換可以描述為:

switch_to(pCur, pNew) //pCur 表示當前進程的PCB,pNew 表示待切換進程的PCB
{
	// 將當前執行進程的狀態保存在PCB中
	pCur.ax = CPU.ax;
	pCur.bx = CPU.bx;
	...
	pCur.cs = CPU.cs;
	pCur.pc = CPU.pc;
	// 加載新的進程的PCB,執行新的進程
	CPU.ax = pNew.ax;
	CPU.bx = pNew.bx;
	...
	CPU.cs = pNew.cs;
	CPU.pc = pNew.pc;
}

3.3 進程的調度策略

由於在就緒隊列中存在多個就緒態的進程,那么在進行進程調度時也必須遵守一定的原則,最常見的是:

  1. 高級調度: 又稱作業調度、長程調度。從輸入系統的一批作業(job, 用戶提交給操作系統計算的一個獨立任務)中按照預定的調度策略挑選若干作業進入內存,為其分配所需資源並創建對應作業的用戶進程。
  2. 中級調度: 又稱平衡調度,中程調度。根據內存資源情況決定內存所能容納的進程數目,並完成外存和內存中進程對換工作。
  3. 低級調度:又稱進程調度/線程調度,短程調度。根據某種原則決定就緒隊列中那個進程/線程先獲得處理器,並將處理器出讓給它使用。

其中常見的低級調度算法主要包括:

  1. 先來先服務(First Come First Server, FCFS)算法。
  2. 最短作業優先(Shortest Job First, SJF)算法。
  3. 最短剩余時間優先(Shortest Remaining Time First, SRTF)算法: 假設當前某進程/線程正在運行,如果有新進程/線程移入就緒隊列,若它所需的CPU運行時間比當前運行的進程/線程所需的剩余CPU時間還短,搶占式最短作業優先算法強行剝奪當前執行者的控制權,調度新進程/線程執行。
  4. 最高響應比優先(Highest Response Ratio First, HRRF)算法:非剝奪式算法。其中,響應比 = (作業已等待時間 + 作業處理時間) / 作業處理時間。
  5. 優先級調度算法:優先級高的選擇進程/線程優先選擇。
  6. 輪轉調度(Round-Robin, RR)算法: 也稱時間片調度。就緒隊列的進程輪流運行一個時間片。
  7. 多級反饋隊列(Multi-Level Feedback Queue, MLFQ)算法。

3.4 多進程之間相互影響

想象一下,如果進程1的程序中有 mov [100], ax 而恰好在這個時刻CPU需要切換到進程2,進程2的開始指令剛好存在100的內存地址中。由於進程1中干擾了內存100中的數據,造成進程2損壞。為了使多個進程能夠在內存中很好地共存,操作系統給每個進程單獨分配一段內存空間,通過映射表將進程中的內存映射為該內存空間的一塊區域。如此,雖然在代碼中所使用的邏輯地址是一樣的,但是通過映射表所得到的實際物理地址是不同的。如下圖所示:

3.5 進程之間的通信

有的時候,多個進程之間需要進行合作,共享同一塊緩沖區,比如打印(PPT,PDF,Word都可以打印),首先每個進程需要往打印隊列中存入數據,由於進程是交替執行的,很有可能出現PPT還沒存完,Word又往隊列中存儲,造成混亂。因此需要設計一種機制來控制進程切換的時機,即:當第一個進程完成時才能切換下一個進程。從上述可以抽象出來一個“生產者-消費者”模型,如下:

while(true){	//生產者進程
	while(counter == BUFFER_SIZE){;}	//BUFFER_SIZE代表緩沖區大小
	buffer[in] = item;	//存入數據
	in = (in+1)%BUFFER_SIZE;
	counter++;	//計數器加1
}
while(true){	//消費者進程
	while(counter == 0){;}	//當緩沖區不為空時,讀出數據
	item = buffer[out];
	out = (out+1)%BUFFER_SIZE;
	counter--;	//計數器減1
}
//其中,counter++ 在匯編中的實際過程為:
register = counter;
register = register+1;
counter = register;

假如初始狀態:counter = 5,那么該執行過程描述為下圖。理論上來講,生產者使得 counter+1,而消費者使得 counter-1,因此完整執行一遍生產者和消費者之后 counter 應該不變,但由於二者交替執行,因此導致了 counter的混亂。

一種解決的辦法是:在生產者執行的時候給 counter 上鎖,如果進程想要切換到消費者,首先檢查是否上鎖,如果上鎖則該時刻不能切換,否則可以切換。優化后的執行過程如下:

參考資料:

https://zhuanlan.zhihu.com/p/164842096
https://www.cnblogs.com/jin-xin/articles/10078845.html
https://www.bilibili.com/video/BV1d4411v7u7?p=9


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM