進程間通信(Linux面試乾貨)

進程間通信(IPC)

爲什麼操作系統要爲用戶提供進程間通信方式?

答:因爲進程的獨立性。每個進程都有自己的獨立虛擬地址空間,操作的都是自己的地址,所以進程之間無法直接進行通信。

進程間通信方式

  1. 從Unix借鑑的:管道- - -資源傳輸;
  2. systemV標準的進程間通信方式:共享共存、消息隊列、信號量

一、管道:傳輸資源- - -傳輸的是數據資源;

本質:內核中的一塊緩衝區,若多個進程可以訪問到同一個緩衝區,就可以實現通信。
分類:匿名管道/命名管道。
匿名管道:內核中的這塊緩衝區沒有具體的標識符,只能用於具有親緣關係的進程間通信。多個進程只要通過子進程複製父進程的方式拿到同一個管道(緩衝區)的操作句柄就可以進行通信。
操作句柄:文件描述符。


在這裏插入圖片描述

創建匿名管道

int pipe(int pipefd[2]); pipefd[2] - - - 具有兩個int型節點的數組的首地址,用於接收創建管道返回的操作句柄

pipefd[0] - - - 用於從管道中讀取數據
pipefd[1] - - - 用於向管道中寫入數據,要不然只能讀,要不然只能寫(單向傳輸);使用的時候如果不使用哪一段,關閉這一端就可以,管道是一個單向的資源傳輸,自身並不能限制資源的傳輸方向;管道是一個半雙工通信(可以選擇方向的單向傳輸)
在這裏插入圖片描述

管道的讀寫特性:

  1. 若管道中沒有數據,則調用read讀取數據會阻塞;
  2. 若管道中數據滿了,則調用write寫入數據會阻塞;管道是一塊緩衝區(內存空間),並非無限制大。
    阻塞:爲了完成一個功能,發起調用,若當前不具備完成條件,則一直等待。
  3. 若管道的所有讀端pipefd[0]被關閉,則繼續調用write會產生異常導致進程退出;
  4. 若管道的所有寫端pipefd[1]被關閉,則繼續調用read,read讀完管道中你那個的數據後不再阻塞,而是返回0;

命令行中管道符的實現:ps -ef |grep ssh
ps -ef :默認將結果打印到標準輸出
grep ssh :默認從標準輸入讀取數據進行過濾

ps進程如何將輸出結果,並不寫入標準輸出而是寫入到管道中呢?- - - -將標準輸出重定向到管道寫入端;
grep進程如何做到不從標準輸入讀取數據,而是從管道讀取數據呢? - - - - 將標準輸入重定向到管道讀取端;
grep過濾了結果後並不會退出,循環讀取數據進行過濾;因此ps進程退出後需要關閉所有寫端,告訴grep沒有人寫了。

命名管道

命名管道是內核中的緩衝區,這塊緩衝區具有標識符,(可用於同一主機上的任意進程間通信) 。這個標識符是一個可建於文件系統的管道文件,能夠被其他進程找到並打開,管道文件則可以獲取管道的操作句柄。
多個進程通過命名管道通信是通過打開命名管道文件訪問同一塊內核中的緩衝區實現通信。

創建管道文件:int mkfifo(char *filename,mode_t mode);

filename:管道文件名稱;
mode:管道文件權限
返回值:成功則返回0,失敗返回-1;
其餘操作與文件IO操作相同

open 打開命名管道的特性

  • 若文件以只讀打開,則會阻塞,直到文件被以寫的方式打開;
  • 若文件以只寫打開,則會阻塞,直到文件被以讀的方式打開。

管道

本質:內核中的一塊緩衝區;
分類

  • 匿名管道- - - - 只能用於具有親緣關係的進程間通信;
  • 命名管道- - - - 可用於同一主機上的任意進程間通信;

特性

  • 管道是半雙工通信(可以選擇方向的單向傳輸);
  • 管道讀寫特性(不管匿名還是命名都是一樣)
    若管道中沒有數據則read會阻塞;若管道中數據滿了則write會阻塞;
    若管道中所有讀端關閉則write會觸發異常;若管道所有寫端關閉則read讀完數據返回0不再阻塞;
  1. 管道生命週期隨進程(打開管道的所有進程退出,管道就會被釋放(命名管道也一樣,本質都是緩衝區,文件只是標識符))。
  2. 管道提供字節流傳輸服務(可靠的、有序的,基於連接的一種靈活性比較高的傳輸服務);
  3. 命名管道額外有一個打開特性:只讀打開則會則會阻塞直到文件以寫方式打開;只寫打開則會阻塞直至文件以讀方式打開;
  4. 管道自帶同步與互斥
    同步:通過條件判斷實現臨界資源操作的合理性;管道中沒有數據則read會阻塞,管道中數據滿了則write會阻塞。
    互斥:通過唯一訪問實現臨界資源操作的安全性;管道的讀寫操作在PIPE_BUF大小以保證操作的原子性。

臨界資源:大家都能訪問到的資源;
原子操作:不能被打斷的操作,指的是一個操作要麼一次完成,要麼就不做。

二、共享內存

特性:1、共享內存是最快的進程間通信方式;2、生命週期隨內核。
注意:共享內存並沒有自帶同步與互斥 - - - - - 多個進程進行訪問的時候存在安全問題;
操作:代碼操作流程/具體的接口 + 命令操作 ipcs/ipcrm。
本質原理
共享內存數據的寫入,是一種針對地址指向空間的覆蓋式寫入。
在這裏插入圖片描述
共享內存的操作流程

  1. 創建共享內存- - - -在物理內存上開闢空間;
  2. 進程將共享內存映射到自己的虛擬地址空間;
  3. 基本的內存操作都可以對這塊空間進行操作;
  4. 不玩了,解除虛擬地址空間與內存的映射關係;
  5. 釋放共享內存資源。

int shmget(key_t key,size_t size,int shmflg); - - - - 創建共享內存

key:內核中共享內存的標識符 - - - - - 多個進程通過相同的標識符才能打開同一個共享內存;
size:共享內存的大小 - - - - - 以內存頁爲單位進行分配;
shmflg:IPC_CREAT存在則打開,不存在則創建 | IPC_EXCL 與 IPC_CREAT同時使用,若存在則報錯,不存在則創建 | mode
返回值:返回一個非負整數- - - - - 共享內存的操作句柄;失敗返回 -1;

key_t ftok(const char* pathname,int proj_id); - - - - -生成一個key值(通過inode節點號與proj_id合成一個key)

void *shmat(int shmid,const void *shmaddr,int shmflg)

shmid:shmget返回的共享內存操作句柄;
shmaddr:共享內存映射在虛擬地址空間的首地址 - - - - - 通常置爲NULL;
shmflg:映射成功之後對共享內存可以進行的操作 , SHM_RDONLY用於只讀(前提是有讀的權限)/0(默認可讀可寫);
返回值:返回共享內存映射在虛擬地址空間中的首地址- - - - 通過這個首地址進行後續的內存操作,失敗返回(void*)-1;

int shmdt(const void* shmaddr); - - - - - 解除映射關係

shmaddr:映射在虛擬地址空間的首地址;
返回值:成功返回0,失敗返回-1;

shmct(int shmid, int cmd, struct shmid_ds *buf); - - - - - 刪除共享內存

shmid:共享內存操作句柄;
cmd:對共享內存想要進行的操作 IPC_RMID (刪除共享內存)
buf:用於獲取/設置共享內存信息的結構,不使用則置NULL;
返回值:成功返回0,失敗返回-1;
共享內存刪除的時候,並不會立即被刪除,只是將其狀態置爲被銷燬狀態,移除標識- - - - 爲了不讓這個共享內存繼續被其他進程映射連接,然後等到當前共享內存映射連接數爲0的時候,纔會真正刪除這塊共享內存。

三、消息隊列

內核中的一個優先級隊列,多個進程通過訪問同一個隊列,進行添加節點或者獲取節點實現通信。
特性:1、自帶同步與互斥; 2、生命週期隨內核。
在這裏插入圖片描述

  • 1、創建消息隊列int msgget(key_t key,int msgflg); - - - (在內核中創建一個優先級隊列)
  • 2、進程可以向隊列中增加節點/獲取節點
int msgsnd( int msqid, const void *msgp, size_t msgsz, int msgflg);
ssize_t msgrcv(int msqid, void *msgp,size_t msgsz,long msgtyp,int msgflg); - - - 指定獲取什麼類型的數據與mtype對應
struct msgbuf
{
//因爲系統頁不知道數據有多長,因此這個結構體由用戶自己定義
long mtype;  //message type,must be>0
char mtext[1];  // message data
};
  • 3、刪除消息隊列
int msgct(int msqid, int cmd, struct msqid_ds *buf);

四、信號量

信號量用於實現進程間的同步與互斥的(共享內存本身是不提供同步與互斥的,操作存在安全問題,因此需要使用信號量保護對共享內存的操作)。
同步:通過條件判斷實現臨界資源訪問的合理性;
互斥:通過同一時間的唯一訪問實現臨界資源訪問的安全性;
本質:一個內核中的計數器 + pcb等待隊列 + 使進程等待/喚醒的接口;
在這裏插入圖片描述
同步:資源能訪問的時候,讓你訪問;不能訪問的時候,讓你等着;等到能訪問了再去喚醒你去訪問;
信號量組成:自身的計數器 + 等待隊列 + 使一個進程等待以及喚醒一個進程的操作。
信號量實現互斥:保證同一時間只能有一個進程能夠訪問資源。
信號量實現互斥思想:所有資源只有一份,只有一個進程能夠獲取,用完了放回來,下一個進程再獲取的思想。

ipcs命令

ipcs:查看進程間通信資源;
-m :查看共享內存;
-q:查看消息隊列;
ipcrm:刪除進程間通信資源;

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