Linux內核-進程間通信組件的實現

Linux內核的五大組件

一個完整的Linux內核一般由五大部分組成,他們分別是內存管理,進程管理,進程間通信,虛擬文件系統和網絡接口。

一、內存管理

內存管理主要完成的是如何合理有效地管理整個系統的物理內存,同時快速響應內核各個子系統對內存分配的請求。Linux內存管理支持虛擬內存,而多餘出的這部分內存就是通過磁盤申請得到的,平時系統只把當前運行的程序塊保留在內存中,其他程序塊則保留在磁盤中。在內存緊缺時,內存管理負責在磁盤和內存間交換程序塊。

二、進程管理

進程管理主要控制系統進程對CPU的訪問。當需要某個進程運行時,由進程調度器根據基於優先級的調度算法啓動新的進程。:Linux支持多任務運行,那麼如何在一個單CPU上支持多任務呢?這個工作就是由進程調度管理來實現的。在系統運行時,每個進程都會分得一定的時間片,然後進程調度器根據時間片的不同,選擇每個進程依次運行,例如當某個進程的時間片用完後,調度器會選擇一個新的進程繼續運行。由於切換的時間和頻率都非常的快,由此用戶感覺是多個程序在同時運行,而實際上,CPU在同一時間內只有一個進程在運行,這一切都是進程調度管理的結果。

進程間通信主要用於控制不同進程之間在用戶空間的同步、數據共享和交換。由於不用的用戶進程擁有不同的進程空間,因此進程間的通信要藉助於內核的中轉來實現。一般情況下,當一個進程等待硬件操作完成時,會被掛起。當硬件操作完成,進程被恢復執行,而協調這個過程的就是進程間的通信機制。

三、進程間通信

進程間通信主要用於控制不同進程之間在用戶空間的同步、數據共享和交換。由於不用的用戶進程擁有不同的進程空間,因此進程間的通信要藉助於內核的中轉來實現。一般情況下,當一個進程等待硬件操作完成時,會被掛起。當硬件操作完成,進程被恢復執行,而協調這個過程的就是進程間的通信機制。

(1)進程間通信的目的

數據傳輸:一個進程需要將它的數據發送給另一個進程;

資源共享:多個進程之間共享同樣的資源;

通知事件:一個進程需要向另一個或者另一組進程發送消息,通知他們發生了某種事件。

進程控制:有些進程需要完全控制另一個進程的執行,此時控制進程希望能夠攔截另一個進程的所有陷入和異常,並能夠及時知道它的狀態改變。

(2)進程間通信方式

進程間通信主要分爲兩大標準:System V 標準和 POSIX 標準。

關於System V標準的進程間通信主要有以下幾類:

1. 管道

管道適用於進程間的數據傳輸。本質上管道是操作系統在內核中爲進程開闢了一塊緩衝區,多個進程通過訪問同一緩衝區進行通信,數據在緩衝區中以讀寫的方式被不同進程獲取和操作。

管道有三大特性:

1.生命週期隨進程;

2.自帶同步與互斥;

3.提供字節流服務。

管道主要分爲匿名管道和命名管道

匿名管道

前面說了管道是操作系統爲進程在內核中分配的一塊緩衝區,匿名管道就是指這塊緩衝區沒有標識符,因此其他進程無法直接訪問匿名管道,只有類似父子進程這樣的具有親緣關係的進程才能使用匿名管道進行通信(原因是子進程會複製父進程的PCB,其中包括這塊信息)。匿名管道的創建使用如下接口:

intpipe(intfd[2])

這個接口的作用是創建一個匿名管道,並向用戶返回這個管道的操作句柄,其中參數fd[2]中fd[0]用於從管道中讀取數據,fd[1]用於從管道中寫入數據,如果創建成功返回 0, 創建失敗返回 -1.

匿名管道的特性是:

1.若管道中沒有數據,使用讀操作會阻塞;

若管道寫滿了,使用寫操作會阻塞;

若管道的寫端關閉了,讀完數據之後不會阻塞而是返回 0;

4.若管道的讀端關閉了,繼續寫入數據會觸發異常,程序退出。

這些特性體現了管道自帶同步與互斥。

命名管道

命名管道和匿名管道相反,命名管道是有標識符的一塊緩衝區,並且這個標識符一般是一個可見於文件系統的文件。所以命名管道是一個特殊類型的文件,其他進程可以通過這個標識符找到這塊緩衝區,即通過打開同一個管道文件,訪問到同一緩衝區,進而實現進程間通信。

創建一個命名管道既可以使用mkfifo filename命令也可以使用接口,函數接口如下:

intmkfifo(constchar* pathname,mode_tmode)

參數pathname是命名管道文件的名稱,mode是文件權限 。如果創建成功返回0,失敗返回-1.

命名管道的打開特性:

1.若管道文件以只讀的方式打開,會阻塞,直到這個文件被以寫的方式打開;

2.若管道文件以只寫的方式打開,會阻塞,直到這個文件被以讀的方式打開;

3.若文件以讀寫的方式打開,就不會阻塞。

不管是匿名還是命名管道,同查那個對管道進行的數據操作的大小不超過PIPE_BUF這個宏的大小,默認是4KB。

2.共享內存

共享內存用於進程間的數據共享,是最快的進程間通信。共享內存的創建大概是以下步驟:首先,在物理內存中開闢一塊空間,將這塊物理內存映射到程序的虛擬地址空間,進程就可以通過虛擬地址來訪問這塊內存。多個進程映射到同一物理內存,這樣進行通信的方式,不需要進入內核,只需要再共享的內存區進行操作即可。其他方式的通信都是因爲內核中的緩衝區,進程在通信的時候會涉及內核態和用戶態的兩次數據拷貝。而共享內存不會所以速度更快。

共享內存的操作流程:

1.創建共享內存即開闢具有標識符的物理內存空間;2.將共享內存映射到各個進程的虛擬地址空間;3.直接通過虛擬地址進行對共享內存的操作;4.解除映射;5.釋放共享內存。

intshmget(key_tkey,intsize,intflag)//創建一個共享內存void*shmat(intshmid,void* addr,intflag)//建立映射intshmdt(void* shmstart)//解除映射intshmctl(intshmid,intcmd, struct shmid_ds* bf)//操作共享內存//cmd參數爲IC_RMID的時候是刪除共享內存

當刪除共享內存的時候,共享內存不會立即被刪除(因爲可能造成正在訪問的進程奔潰)而是將key修改成0,表示這塊共享內存不會再接收映射鏈接,當這塊共享內存的映射鏈接爲0的時候,則自動釋放。

需要注意的是共享內存自帶沒有同步與互斥。

3. 消息隊列

消息隊列用於進程間的數據傳輸(有標識符)

消息隊列實際上就是內核中的一個優先級隊列,多個進程通過向同一個隊列中 添加 或者 獲取 節點來實現通信。主要是傳輸一個有類型(優先級)的數據塊。

特性:

1.自帶同步與互斥;

2.生命週期隨內核;

3.數據傳輸自帶優先級。

信號量

信號量用於實現進程間的控制,主要是同步和互斥。

本質:內核中的一個計數器(對資源進行計數) + pcb等待隊列

互斥的實現:通過只有 0 / 1 的計數器,實現對臨界資源訪問狀態的標記,在訪問臨界資源

之前先獲取信號量,計數 -1;若計數 <0 則使進程等待(將進程pcb加入隊列中);否則可

以對臨界資源進行訪問(並且在訪問期間,已經將臨界資源的狀態置爲不可訪問狀態,因此

可一保證其他進程不會再訪問臨界資源。當前進程訪問完畢之後,則對計數進行+1,則喚醒

一個進程(將一個pcb出隊,置爲運行狀態)

同步的實現:信號量是一個對資源的計數,可以通過計數判斷是否能夠獲取一個資源進行處

理;若計數小於 0,則表示不能獲取(並且對計數進行 -1),需要等待(加入pcb隊列)。

這時候若其他進程生產一個資源,則會對計數進行 +1,若計數 <= 0 ,則喚醒一個進程。

(負數表示正在等待進程的數量,如果爲正說明沒有進程需要資源)。

四、虛擬文件系統

Linux內核中的虛擬文件系統用一個通用的文件模型表示了各種不同的文件系統,這個文件模型屏蔽了很多具體文件系統的差異,使Linux內核支持很多不同的文件系統,這個文件系統可以分爲邏輯文件系統和設備驅動程序:邏輯文件系統指Linux所支持的文件系統,例如ext2、ext3和fat等;設備驅動程序指爲每一種硬件控制器所編寫的設備驅動程序模塊。

五、網絡接口

網絡接口提供了對各種網絡標準的實現和各種網絡硬件的支持。網絡接口一般分爲網絡協議和網絡驅動程序。網絡協議部分負責實現每一種可能的網絡傳輸協議。網絡設備驅動程序則主要負責與硬件設備進行通信,每一種可能的網絡硬件設備都有相應的設備驅動程序。

免費分享學習資料(C/C++,Linux,golang,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,ffmpeg,TCP/IP,協程,DPDK,嵌入式)等,轉發+關注後 

文檔點擊這裏獲取

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章