Docker原理解讀
735
2025-03-31
文章目錄
進程是什么?
并行和并發有什么區別嗎?
進程什么時候會被創建,并生成PBC?
進程怎么初始化的?
進程的狀態?
五種狀態模型
七種狀態模型
什么會有掛起狀態?
掛起狀態有什么?
進程控制塊(進程控制結構)
PBC具體包含什么呢?
每個PBC如何組織起來的呢?
就緒隊列和阻塞隊列的鏈表的組織形式?
進程如何切換?
進程切換定義?
進程切換步驟?
上下問切換的場景有哪些?
線程
什么是線程?
線程的上下文切換?
進程與線程的區別?
進程如何調度?
什么是進程調度?
什么時候調度進程?
調度算法分類?
以什么原則調度進程?
進程調度的算法有什么?
先來先服服務(非搶占式)
時間片輪轉(搶占式)
最短作業優先
最短剩余時間優先
優先級調度
多級反饋隊列調度
進程通信之管道
進程通信之消息隊列
什么是消息隊列?
消息隊列保存在哪?
缺點
進程通信之共享內存
進程通信之信號量
進程通信之信號
進程通信之Socket
總結
進程是什么?
1、進程指的是當我們啟動一個程序,運行之后就是一個進程,進程也可以抽象為任務,一個進程對應一個任務或者多個任務。
2、進程是系統進行資源分配和調度的基本單位,是操作系統結構的基礎。
并行和并發有什么區別嗎?
并行指的是多核CPU,同時運行在某一個時間點。
并發指的是單核cpu上切換任務,形成一種并發執行。
進程什么時候會被創建,并生成PBC?
1、系統初始化
2、通過系統api創建
3、批處理作業初始化
4、有現有進程派生子進程(如fork子進程)
進程怎么初始化的?
給新進程分配一個進程ID
分配內存空間
初始化PCB
進入就緒隊列
進程的狀態?
五種狀態模型
粗的:
細的:
解釋:
如圖,進入就緒隊列,其狀態就會變為就緒態。各個狀態之間的關系描述如下:
就緒 -> 運行
:當操作系統內存在著調度程序,當需要運行一個新進程時,調度程序選擇一個就緒態的進程,讓其進入運行態。
運行 -> 就緒
:運行態的進程,會占有CPU(參照一開始的餅狀圖)。每個進程會被分配一定的執行時間,當時間結束后,重新回到就緒態。
運行 -> 阻塞
:進程請求調用系統的某些服務,但是操作系統沒法立即給它(比如這種服務可能要耗時初始化,比如I/O資源需要等待),那么它就會進入阻塞態。
阻塞 -> 就緒
:當等待結束了,就由阻塞態進入就緒態。
運行 -> 終止
:當進程表示自己已經完成了,它會被操作系統終止。
七種狀態模型
粗:
細:
什么會有掛起狀態?
為了解決內存占用問題,可以將一部分內存中的進程交換到磁盤中,這些被交換到磁盤的進程,會進入掛起狀態。
掛起狀態有什么?
阻塞掛起狀態:進程在外存(硬盤)并等待某個事件的出現;
就緒掛起狀態:進程在外存(硬盤),但只要進入內存,即刻立刻運行;
進程控制塊(進程控制結構)
1、在操作系統中,是用進程控制塊(process control block,PCB)數據結構來描述進程的。
2、PCB 是進程存在的唯一標識,
3、意味著一個進程的存在,必然會有一個 PCB,如果進程消失了,那么 PCB 也會隨之消失。
PBC具體包含什么呢?
每個PBC如何組織起來的呢?
1、通過鏈表的方式進行組織,把具有相同狀態的進程鏈在一起,組成各種隊列。
將所有處于就緒狀態的進程鏈在一起,稱為就緒隊列;
把所有因等待某事件而處于等待狀態的進程鏈在一起就組成各種阻塞隊列;
另外,對于運行隊列在單核 CPU 系統中則只有一個運行指針了,因為單核 CPU 在某個時間,只能運行一個程序。
就緒隊列和阻塞隊列的鏈表的組織形式?
除了鏈接的組織方式,還有索引方式,它的工作原理:將同一狀態的進程組織在一個索引表中,索引表項指向相應的 PCB,不同狀態對應不同的索引表。
一般會選擇鏈表,因為可能面臨進程創建,銷毀等調度導致進程狀態發生變化,所以鏈表能夠更加靈活的插入和刪除。
進程如何切換?
進程切換定義?
當一個正在運行中的進程被中斷,操作系統指定另一個就緒態的進程進入運行態,這個過程就是進程切換,也可以叫上下文切換。
進程切換步驟?
保存處理器上下文環境:將CPU程序計數器和寄存器的值保存到當前進程的私有堆棧里
更新當前進程的PCB(包括狀態更變)
將當前進程移到就緒隊列或者阻塞隊列
根據調度算法,選擇就緒隊列中一個合適的新進程,將其更改為運行態
更新內存管理的數據結構
新進程內對堆棧所保存的上下文信息載入到CPU的寄存器和程序計數器,占有CPU
上下問切換的場景有哪些?
為了保證所有進程可以得到公平調度,CPU 時間被劃分為一段段的時間片,這些時間片再被輪流分配給各個進程。這樣,當某個進程的時間片耗盡了,就會被系統掛起,切換到其它正在等待 CPU 的進程運行;
進程在系統資源不足(比如內存不足)時,要等到資源滿足后才可以運行,這個時候進程也會被掛起,并由系統調度其他進程運行;
當進程通過睡眠函數 sleep 這樣的方法將自己主動掛起時,自然也會重新調度;
當有優先級更高的進程運行時,為了保證高優先級進程的運行,當前進程會被掛起,由高優先級進程來運行;
發生硬件中斷時,CPU 上的進程會被中斷掛起,轉而執行內核中的中斷服務程序;
線程
什么是線程?
線程是進程當中的?條執?流程。
同?個進程內多個線程之間可以共享代碼段、數據段、打開的?件等資源,但每個線程各?都有?套獨?的寄存器和棧,這樣可以確保線程的控制流是相對獨?的。
3、線程是CPU調度的基本單位。(操作系統底層存在調度程序,調度程序可調度任務,而單線程進程,每個進程可以對應一個任務。現在,對于多線程的進程,每一個線程最終對于調度程序來說,都是一個任務,如下圖(Linux系統))
線程的上下文切換?
當兩個線程不是屬于同一個進程,則切換的過程就跟進程上下文切換一樣;
當兩個線程是屬于同一個進程,因為虛擬內存是共享的,所以在切換時,虛擬內存這些資源就保持不動,只需要切換線程的私有數據、寄存器等不共享的數據;
總的來說:線程的上下文切換相比進程,開銷要小很多。
進程與線程的區別?
線程是調度的基本單位,而進程則是資源擁有的基本單位。
所以,所謂操作系統的任務調度,實際上的調度對象是線程,而進程只是給線程提供了虛擬內存、全局變量等資源。
對于線程和進程,我們可以這么理解:
當進程只有一個線程時,可以認為進程就等于線程;
當進程擁有多個線程時,這些線程會共享相同的虛擬內存和全局變量等資源,這些資源在上下文切換時是不需要修改的;
另外,線程也有自己的私有數據,比如棧和寄存器等,這些在上下文切換時也是需要保存的。
進程如何調度?
什么是進程調度?
上下問切換,不能進程切換狀態,搶CPU資源。
什么時候調度進程?
從就緒態 -> 運行態:當進程被創建時,會進入到就緒隊列,操作系統會從就緒隊列選擇一個進程運行;
從運行態 -> 阻塞態:當進程發生 I/O 事件而阻塞時,操作系統必須另外一個進程運行;
從運行態 -> 結束態:當進程退出結束后,操作系統得從就緒隊列選擇另外一個進程運行;
調度算法分類?
非搶占式調度算法挑選一個進程,然后讓該進程運行直到被阻塞,或者直到該進程退出,才會調用另外一個進程,也就是說不會理時鐘中斷這個事情。
搶占式調度算法挑選一個進程,然后讓該進程只運行某段時間,如果在該時段結束時,該進程仍然在運行時,則會把它掛起,接著調度程序從就緒隊列挑選另外一個進程。這種搶占式調度處理,需要在時間間隔的末端發生時鐘中斷,以便把 CPU 控制返回給調度程序進行調度,也就是常說的時間片機制。
以什么原則調度進程?
CPU 利用率:調度程序應確保 CPU 是始終匆忙的狀態,這可提高 CPU 的利用率;
系統吞吐量:吞吐量表示的是單位時間內 CPU 完成進程的數量,長作業的進程會占用較長的 CPU 資源,因此會降低吞吐量,相反,短作業的進程會提升系統吞吐量;
周轉時間:周轉時間是進程運行和阻塞時間總和,一個進程的周轉時間越小越好;
等待時間:這個等待時間不是阻塞狀態的時間,而是進程處于就緒隊列的時間,等待的時間越長,用戶越不滿意;
響應時間:用戶提交請求到系統第一次產生響應所花費的時間,在交互式系統中,響應時間是衡量調度算法好壞的主要標準。
進程調度的算法有什么?
先來先服服務(非搶占式)
先來先服務(First Come First Serverd, FCFS)。先進就緒隊列,則先被調度,先來先服務是最簡單的調度算法。
時間片輪轉(搶占式)
每一個進程會被分配一個時間片,表示允許該進程在這個時間段運行,如果時間結束了,進程還沒運行完畢,那么會通過搶占式調度,將CPU分配給其他進程,該進程回到就緒隊列。這是一種最簡單最公平的調度算法,但是有可能會存在問題。由于進程的切換,需要耗費時間,如果時間片太短,頻繁進行切換,會影響效率。如果進程時間片太長,有可能導致排后面的進程等待太長時間。因此時間片的長度,需要有大致合理的數值。(建議時間片長度在20ms~50ms)
最短作業優先
最短作業優先(Shortest Job First, SJF),顧名思義即進程按照作業時間長短排隊,作業時間段的排前面先執行,如下圖。
缺點:長作業可能一輩子都運行不了,當短作業特別多的時候,周期太長。
最短剩余時間優先
最短剩余時間優先(Shortest Remaining Time Next),從就緒隊列中選擇剩余時間最短的進程進行調度。該算法可以理解最短作業優先和時間片輪轉的結合。如果沒有時間片,那么最短剩余時間其實就是最短作業時間,因為每個進程都是從頭執行到尾。
優先級調度
就緒隊列存在的進程
按照優先級調度,執行順序為p1->p3->p2。如果多個進程優先級相同,則按照先來先服務的方式依次執行。
優先級調度可以進一步細分為搶占式和非搶占式。
非搶占式:和上面提及的非搶占式類似,一旦該進程占有CPU就將一直執行到結束或者阻塞。
搶占式:進程執行期間,一旦有更高優先級的進程進入就緒隊列,那么該進程就會被暫停,重回就緒隊列,讓更高優先級的進程執行。但是為了防止最高優先級進程一直執行,每個進程依然有自己的時間片,每次時間片結束后,會根據一定規則降低該進程優先級,避免某些最高優先級長作業進程一直占用CPU。
缺點:低優先級的可能永遠都不會執行。
多級反饋隊列調度
多級反饋隊列調度基于時間片輪轉和優先級調度,設置多個就緒隊列,賦予每個就緒隊列優先級,優先級越高的隊列進程的時間片越短。如下圖,第1級就緒隊列優先級最高,進程的時間片長度最短,第2級就緒隊列次之,以此類推。
每個進程的用戶地址空間都是獨立的,一般而言是不能互相訪問的,但內核空間是每個進程都共享的,所以進程之間要通信必須通過內核。
進程通信之管道
1、管道傳輸數據是單向的
2、管道這種通信方式效率低,不適合進程間頻繁地交換數據
3、它的好處,自然就是簡單,同時也我們很容易得知管道里的數據已經被另一個進程讀取了。
4、對于匿名管道,它的通信范圍是存在父子關系的進程。(ps auxf | grep mysql)
5、對于命名管道,它可以在不相關的進程間也能相互通信。(mkfifo)
匿名:
命名:
進程通信之消息隊列
什么是消息隊列?
A 進程要給 B 進程發送消息,A 進程把數據放在對應的消息隊列后就可以正常返回了,B 進程需要的時候再去讀取數據就可以了。同理,B 進程要給 A 進程發送消息也是如此。
消息隊列保存在哪?
息隊列是保存在內核中的消息鏈表,在發送數據時,會分成一個一個獨立的數據單元,也就是消息體(數據塊),消息體是用戶自定義的數據類型,消息的發送方和接收方要約定好消息體的數據類型,所以每個消息體都是固定大小的存儲塊,不像管道是無格式的字節流數據。如果進程從消息隊列中讀取了消息體,內核就會把這個消息體刪除。
消息隊列生命周期隨內核,如果沒有釋放消息隊列或者沒有關閉操作系統,消息隊列會一直存在,而前面提到的匿名管道的生命周期,是隨進程的創建而建立,隨進程的結束而銷毀。
缺點
消息隊列通信過程中,存在用戶態與內核態之間的數據拷貝開銷,因為進程寫入數據到內核中的消息隊列時,會發生從用戶態拷貝數據到內核態的過程,同理另一進程讀取內核中的消息數據時,會發生從內核態拷貝數據到用戶態的過程。
進程通信之共享內存
共享內存的機制,就是拿出一塊虛擬地址空間來,映射到相同的物理內存中。
優點:不需要拷貝,大大提高了進程間通信的速度
進程通信之信號量
信號量其實是一個整型的計數器,主要用于實現進程間的互斥與同步,而不是用于緩存進程間通信的數據。(阻止ABA問題)
信號量表示資源的數量,控制信號量的方式有兩種原子操作:
一個是 P 操作,這個操作會把信號量減去 -1,相減后如果信號量 < 0,則表明資源已被占用,進程需阻塞等待;相減后如果信號量 >= 0,則表明還有資源可使用,進程可正常繼續執行。
另一個是 V 操作,這個操作會把信號量加上 1,相加后如果信號量 <= 0,則表明當前有阻塞中的進程,于是會將該進程喚醒運行;相加后如果信號量 > 0,則表明當前沒有阻塞中的進程;
P 操作是用在進入共享資源之前,V 操作是用在離開共享資源之后,這兩個操作是必須成對出現的。
接下來,舉個例子,如果要使得兩個進程互斥訪問共享內存,我們可以初始化信號量為 1。
具體的過程如下:
進程 A 在訪問共享內存前,先執行了 P 操作,由于信號量的初始值為 1,故在進程 A 執行 P 操作后信號量變為 0,表示共享資源可用,于是進程 A 就可以訪問共享內存。
若此時,進程 B 也想訪問共享內存,執行了 P 操作,結果信號量變為了 -1,這就意味著臨界資源已被占用,因此進程 B 被阻塞。
直到進程 A 訪問完共享內存,才會執行 V 操作,使得信號量恢復為 0,接著就會喚醒阻塞中的線程 B,使得進程 B 可以訪問共享內存,最后完成共享內存的訪問后,執行 V 操作,使信號量恢復到初始值 1。
可以發現,信號初始化為 1,就代表著是互斥信號量,它可以保證共享內存在任何時刻只有一個進程在訪問,這就很好的保護了共享內存。
另外,在多進程里,每個進程并不一定是順序執行的,它們基本是以各自獨立的、不可預知的速度向前推進,但有時候我們又希望多個進程能密切合作,以實現一個共同的任務。
例如,進程 A 是負責生產數據,而進程 B 是負責讀取數據,這兩個進程是相互合作、相互依賴的,進程 A 必須先生產了數據,進程 B 才能讀取到數據,所以執行是有前后順序的。
那么這時候,就可以用信號量來實現多進程同步的方式,我們可以初始化信號量為 0。
具體過程:
如果進程 B 比進程 A 先執行了,那么執行到 P 操作時,由于信號量初始值為 0,故信號量會變為 -1,表示進程 A 還沒生產數據,于是進程 B 就阻塞等待;
接著,當進程 A 生產完數據后,執行了 V 操作,就會使得信號量變為 0,于是就會喚醒阻塞在 P 操作的進程 B;
最后,進程 B 被喚醒后,意味著進程 A 已經生產了數據,于是進程 B 就可以正常讀取數據了。
可以發現,信號初始化為 0,就代表著是同步信號量,它可以保證進程 A 應在進程 B 之前執行。
進程通信之信號
1、信號是進程間通信機制中唯一的異步通信機制。
**2、**進程需要為信號設置相應的監聽處理,當收到特定信號時,執行相應的操作,類似很多編程語言里的通知機制。
3、如kill,Ctrl+C,Ctrl+Z都是信號
進程通信之Socket
1、跨網絡與不同主機上的進程之間通信,就需要 Socket 通信了
**2、**Socket 通信不僅可以跨網絡與不同主機的進程間通信,還可以在同主機上進程間通信
總結
任務調度 數據結構
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。