進程管理
進程和線程
參考博客https://github.com/CyC2018/CS-Notes
進程
進程是資源分配的基本單位。
進程控制塊 (Process Control Block, PCB) 描述進程的基本信息和運行狀態,所謂的創建進程和撤銷進程,都是指對 PCB 的操作。
下圖顯示了 4 個程序創建了 4 個進程,這 4 個進程可以並發地執行。
線程
線程是獨立調度的基本單位。
一個進程可以有多線程,他們共享進程資源
QQ 和瀏覽器是兩個進程,瀏覽器進程里面有很多線程,
例如 HTTP 請求線程、事件響應線程、渲染線程等等,線程的並發執行使得在瀏覽器中點擊一個新鏈接從而發起 HTTP 請求時,瀏覽器還可以響應用戶的其它事件。
區別:
Ⅰ 擁有資源
進程是資源分配的基本單位,但是線程不擁有資源,線程可以訪問隸屬進程的資源。
Ⅱ 調度
線程是獨立調度的基本單位,在同一進程中,線程的切換不會引起進程切換,從一個進程中的線程切換到另一個進程中的線程時,會引起進程切換。
Ⅲ 系統開銷
由於創建或撤銷進程時,系統都要為之分配或回收資源,如內存空間、I/O 設備等,所付出的開銷遠大於創建或撤銷線程時的開銷。類似地,在進行進程切換時,涉及當前執行進程 CPU 環境的保存及新調度進程 CPU 環境的設置,而線程切換時只需保存和設置少量寄存器內容,開銷很小。
Ⅳ 通信方面
線程間可以通過直接讀寫同一進程中的數據進行通信,但是進程通信需要借助 IPC。
進程的常見狀態,如何轉換(進程切換的幾種方式)
- 就緒:進程已處於准備好運行的狀態,即進程已分配到除CPU外的所有必要資源后,只要再獲得CPU,便可立即執行。
- 執行:進程已經獲得CPU,程序正在執行狀態。
- 阻塞:正在執行的進程由於發生某事件(如I/O請求、申請緩沖區失敗等)暫時無法繼續執行的狀態。
- 只有就緒態和運行態可以相互轉換,其它的都是單向轉換。就緒狀態的進程通過調度算法從而獲得 CPU 時間,轉為運行狀態; 而運行狀態的進程,在分配給它的 CPU 時間片用完之后就會轉為就緒狀態,等待下一次調度。
- 阻塞狀態是缺少需要的資源從而由運行狀態轉換而來,但是該資源不包括 CPU 時間,缺少 CPU 時間會從運行態轉換為就緒態。
進程調度算法
1. 批處理系統
批處理系統沒有太多的用戶操作,在該系統中,調度算法目標是保證吞吐量和周轉時間(從提交到終止的時間)。
1.1 先來先服務 first-come first-serverd(FCFS)
非搶占式的調度算法,按照請求的順序進行調度。
有利於長作業,但不利於短作業,因為短作業必須一直等待前面的長作業執行完畢才能執行,而長作業又需要執行很長時間,造成了短作業等待時間過長。
1.2 短作業優先 shortest job first(SJF)
非搶占式的調度算法,按估計運行時間最短的順序進行調度。
長作業有可能會餓死,處於一直等待短作業執行完畢的狀態。因為如果一直有短作業到來,那么長作業永遠得不到調度。
1.3 最短剩余時間優先 shortest remaining time next(SRTN)
最短作業優先的搶占式版本,按剩余運行時間的順序進行調度。 當一個新的作業到達時,其整個運行時間與當前進程的剩余時間作比較。
如果新的進程需要的時間更少,則掛起當前進程,運行新的進程。否則新的進程等待。
2. 交互式系統
交互式系統有大量的用戶交互操作,在該系統中調度算法的目標是快速地進行響應。
2.1 時間片輪轉
將所有就緒進程按 FCFS 的原則排成一個隊列,每次調度時,把 CPU 時間分配給隊首進程,該進程可以執行一個時間片。
當時間片用完時,由計時器發出時鍾中斷,調度程序便停止該進程的執行,並將它送往就緒隊列的末尾,同時繼續把 CPU 時間分配給隊首的進程。
時間片輪轉算法的效率和時間片的大小有很大關系:
- 因為進程切換都要保存進程的信息並且載入新進程的信息,如果時間片太小,會導致進程切換得太頻繁,在進程切換上就會花過多時間。
- 而如果時間片過長,那么實時性就不能得到保證。
2.3 多級反饋隊列
一個進程需要執行 100 個時間片,如果采用時間片輪轉調度算法,那么需要交換 100 次。
多級隊列是為這種需要連續執行多個時間片的進程考慮,它設置了多個隊列,每個隊列時間片大小都不同,例如 1,2,4,8,..。進程在第一個隊列沒執行完,就會被移到下一個隊列。這種方式下,之前的進程只需要交換 7 次。
每個隊列優先權也不同,最上面的優先權最高。因此只有上一個隊列沒有進程在排隊,才能調度當前隊列上的進程。
可以將這種調度算法看成是時間片輪轉調度算法和優先級調度算法的結合。
3. 實時系統
實時系統要求一個請求在一個確定時間內得到響應。
分為硬實時和軟實時,前者必須滿足絕對的截止時間,后者可以容忍一定的超時。
進程同步/線程同步幾種方式操作
進程同步的主要任務:是對多個相關進程在執行次序上進行協調,以使並發執行的諸進程之間能有效地共享資源和相互合作,從而使程序的執行具有可再現性。
同步機制遵循的原則:
(1)空閑讓進;
(2)忙則等待(保證對臨界區的互斥訪問);
(3)有限等待(有限代表有限的時間,避免死等);
(4)讓權等待,(當進程不能進入自己的臨界區時,應該釋放處理機,以免陷入忙等狀態)。
1. 臨界區
對臨界資源進行訪問的那段代碼稱為臨界區。
為了互斥訪問臨界資源,每個進程在進入臨界區之前,需要先進行檢查。
2. 同步與互斥
- 同步:多個進程按一定順序執行;
- 互斥:多個進程在同一時刻只有一個進程能進入臨界區
3. 信號量
信號量(Semaphore)是一個整型變量,可以對其執行 down 和 up 操作,也就是常見的 P 和 V 操作。
- down : 如果信號量大於 0 ,執行 -1 操作;如果信號量等於 0,進程睡眠,等待信號量大於 0;
- up :對信號量執行 +1 操作,喚醒睡眠的進程讓其完成 down 操作。
down 和 up 操作需要被設計成原語,不可分割,通常的做法是在執行這些操作的時候屏蔽中斷。
如果信號量的取值只能為 0 或者 1,那么就成為了 互斥量(Mutex) ,0 表示臨界區已經加鎖,1 表示臨界區解鎖。
生產者消費者問題
讀者和寫者問題
哲學家就餐問題
進程通信IPC
進程同步與進程通信很容易混淆,它們的區別在於:
- 進程同步:控制多個進程按一定順序執行;
- 進程通信:進程間傳輸信息。
進程通信是一種手段,而進程同步是一種目的。也可以說,為了能夠達到進程同步的目的,需要讓進程進行通信,傳輸一些進程同步所需要的信息。
進程間通信(IPC,InterProcess Communication)是指在不同進程之間傳播或交換信息。
IPC的方式通常有管道(包括無名管道和命名管道)、消息隊列、信號量、共享存儲、Socket、Streams等。其中 Socket和Streams支持不同主機上的兩個進程IPC
管道(pipe)及命名管道(named pipe):管道可用於具有親緣關系的父子進程間的通信,有名管道除了具有管道所具有的功能外,它還允許無親緣關系進程間的通信;
信號(signal):信號是一種比較復雜的通信方式,用於通知接收進程某個事件已經發生;
消息隊列:消息隊列是消息的鏈接表,它克服了上兩種通信方式中信號量有限的缺點,具有寫權限得進程可以按照一定得規則向消息隊列中添加新信息;對消息隊列有讀權限得進程則可以從消息隊列中讀取信息;
共享內存:可以說這是最有用的進程間通信方式。它使得多個進程可以訪問同一塊內存空間,不同進程可以及時看到對方進程中對共享內存中數據得更新。這種方式需要依靠某種同步操作,如互斥鎖和信號量等;
信號量:主要作為進程之間及同一種進程的不同線程之間得同步和互斥手段;
套接字:這是一種更為一般得進程間通信機制,它可用於網絡中不同機器之間的進程間通信,應用非常廣泛。
1. 管道
管道是通過調用 pipe 函數創建的,fd[0] 用於讀,fd[1] 用於寫。
#include <unistd.h> int pipe(int fd[2]);
它具有以下限制:
- 只支持半雙工通信(單向交替傳輸);
- 只能在父子進程中使用。
2. FIFO
也稱為命名管道,去除了管道只能在父子進程中使用的限制。
3. 消息隊列
相比於 FIFO,消息隊列具有以下優點:
- 消息隊列可以獨立於讀寫進程存在,從而避免了 FIFO 中同步管道的打開和關閉時可能產生的困難;
- 避免了 FIFO 的同步阻塞問題,不需要進程自己提供同步方法;
- 讀進程可以根據消息類型有選擇地接收消息,而不像 FIFO 那樣只能默認地接收。
4. 信號量
它是一個計數器,用於為多個進程提供對共享數據對象的訪問。
5. 共享存儲
允許多個進程共享一個給定的存儲區。因為數據不需要在進程之間復制,所以這是最快的一種 IPC。
需要使用信號量用來同步對共享存儲的訪問。
多個進程可以將同一個文件映射到它們的地址空間從而實現共享內存。另外 XSI 共享內存不是使用文件,而是使用內存的匿名段。
6. 套接字
與其它通信機制不同的是,它可用於不同機器間的進程通信。
死鎖
定義:如果一組進程中的每一個進程都在等待僅由該組進程中的其他進程才能引發的事件,那么該組進程就是死鎖的。
或者在兩個或多個並發進程中,如果每個進程持有某種資源而又都等待別的進程釋放它或它們現在保持着的資源,在未改變這種狀態之前都不能向前推進,稱這一組進程產生了死鎖。通俗地講,就是兩個或多個進程被無限期地阻塞、相互等待的一種狀態。
死鎖產生的原因:系統資源不足,進程推進順序非法
產生死鎖的必要條件:
-
互斥條件(Mutual exclusion):資源不能被共享,只能由一個進程使用。(一個資源每次只能被一個進程使用;若其他進程申請使用該資源,必須等到該資源被釋放為止)
-
請求與保持條件(Hold and wait):一個進程因請求資源而阻塞時,對已獲得的資源保持不放。
-
非搶占條件(No pre-emption):已經分配的資源不能從相應的進程中被強制地剝奪。
-
循環等待條件(Circular wait):系統中若干進程組成環路,該環路中每個進程都在等待相鄰進程正占用的資源。
死鎖預防
死鎖預防的基本思想是 只要確保死鎖發生的四個必要條件中至少有一個不成立,就能預防死鎖的發生
處理死鎖有四種方法:
- 鴕鳥策略
- 死鎖檢測與死鎖恢復
- 死鎖預防
- 死鎖避免
鴕鳥策略:
把頭埋在沙子里,假裝根本沒發生問題。
因為解決死鎖問題的代價很高,因此鴕鳥策略這種不采取任務措施的方案會獲得更高的性能。
當發生死鎖時不會對用戶造成多大影響,或發生死鎖的概率很低,可以采用鴕鳥策略。
大多數操作系統,包括 Unix,Linux 和 Windows,處理死鎖問題的辦法僅僅是忽略它。
死鎖恢復:
- 利用搶占恢復
- 利用回滾恢復
- 通過殺死進程恢復
死鎖預防
在程序運行之前預防發生死鎖
1. 破壞互斥條件
例如假脫機打印機技術允許若干個進程同時輸出,唯一真正請求物理打印機的進程是打印機守護進程。
2. 破壞占有和等待條件
一種實現方式是規定所有進程在開始執行前請求所需要的全部資源。
3. 破壞不可搶占條件
4. 破壞環路等待
給資源統一編號,進程只能按編號順序來請求資源。
死鎖避免
在程序運行時避免發生死鎖。