1. 前言
上一小結(jié)談到了操作系統(tǒng)中進(jìn)程和線程的區(qū)別,其中進(jìn)程之間、線程之間的通信方式不同,進(jìn)程通信(Inter-Process Communication,簡(jiǎn)稱 IPC)是指不同進(jìn)程之間交換信息。操作系統(tǒng)中時(shí)刻都在進(jìn)行 IPC,例如微信讀取本地的文件,就是微信程序和文件系統(tǒng)進(jìn)程交互的過程。
2. 進(jìn)程間通信
面試官提問: 操作系統(tǒng)進(jìn)程之間的通信方式有哪些?有什么特點(diǎn)?
題目解析:
操作系統(tǒng)中最常用的 IPC 方式有 5 種,分別是管道、命名管道、信號(hào)、共享內(nèi)存以及套接字。
2.1 管道
管道(pipe),默認(rèn)指無名管道。管道在兩個(gè)進(jìn)程之間建立一個(gè)通道,一個(gè)進(jìn)程向這個(gè)通道寫入字節(jié)流,另一個(gè)進(jìn)程從這個(gè)通道讀取字節(jié)流。用 C 語言描述管道示例:
#include <unistd.h> // 引入linux頭文件
int pipe(int fd[2]); // 返回:如果成功返回0,失敗則返回-1
上述定義的 fd 對(duì)象,其中 fd[0]
表示讀文件描述符,f[1]
表示寫文件描述符。
假設(shè)存在兩個(gè)進(jìn)程,分別為進(jìn)程 A 和進(jìn)程 B,那么進(jìn)程 A 往 f[1]
寫入,進(jìn)程 B 則從自身的 f[0]
讀取內(nèi)容。
需要注意管道是半雙工通信,也就是數(shù)據(jù)的流向是固定的,必須有一端是寫入端,另一端是讀取端。
2.2 信號(hào)
信號(hào)(Signal)是 Unix 系統(tǒng)中就已有的 IPC 方式,繼承于 Unix 的 Linux 系統(tǒng)和 MacOS 系統(tǒng)也具有相同的通信方式。
信號(hào)的工作原理是向某個(gè)進(jìn)程發(fā)送特定的消息,目標(biāo)進(jìn)程在收到消息之后,就知道特定事件已經(jīng)發(fā)生,此時(shí)進(jìn)程可以忽略消息即不做處理,或者是處理消息調(diào)用固定的函數(shù)。
以 MacOS 為例,在 shell 終端輸入 kill -l
可以列出支出的全部信號(hào)名稱:HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS PIPE ALRM TERM URG STOP
。
2.3 共享內(nèi)存
共享內(nèi)容(Shared Memory)是指兩個(gè)進(jìn)程之間可以讀和寫相同的操作系統(tǒng)內(nèi)存空間,每個(gè)進(jìn)程的操作對(duì)另外的進(jìn)程都是可見的,這種通信方式非常類似線程之間的通信。
C 語言實(shí)現(xiàn)的共享內(nèi)存步驟:
(1)shmget()
:創(chuàng)建一段共享內(nèi)存,或者引用已有的共享內(nèi)存的空間;
(2)shmat()
:連接已有的共享內(nèi)存的地址;
(3)shmctl()
:建立連接之后,對(duì)共享內(nèi)存進(jìn)行讀寫操作;
(4)shmdt()
:所有操作都執(zhí)行完成之后,斷開連接。
2.4 命名管道
命名管道(Named Pipe)實(shí)際上就是先進(jìn)先出隊(duì)列(First In First Out,簡(jiǎn)稱 FIFO),候選人需要區(qū)分命名管道和管道,兩者最大的區(qū)別在于管道只能在具有親緣關(guān)系的兩個(gè)進(jìn)程之間通信,例如父子進(jìn)程之間或者兄弟進(jìn)程之間,命名管道則可以在任何兩個(gè)進(jìn)程之間通信,更加零活。
如圖所示,用戶進(jìn)程 A 是寫入進(jìn)程,寫入的消息是 1 2 3 4 5
,因?yàn)樽裱冗M(jìn)先出的原則,用戶進(jìn)程 B 讀出的消息順序也是 1 2 3 4 5
。
2.5 套接字
上述介紹的 IPC 方式都是同一個(gè)主機(jī)內(nèi)進(jìn)程的交互方式,都是本地通信,套接字(Socket)一般用來處理不同主機(jī)進(jìn)程之間的通信,也就是遠(yuǎn)程通信,是網(wǎng)絡(luò)通信最常用的方式。Socket 通信需要 TCP 或者 UDP 協(xié)議的支持。使用 C 語言創(chuàng)建 Socket 的示例:
#include <sys/types.h>
#include <sys/socket.h> //引入頭文件
int socket(int domain, int type, int protocol); //創(chuàng)建一個(gè)socket
3. 小結(jié)
本章節(jié)介紹了 5 種最常見的進(jìn)程間通信方式,候選人需要掌握沒種通信方式的原理,最好能夠畫出原型圖,而操作系統(tǒng)級(jí)別的通信一般不需要我們手動(dòng)實(shí)現(xiàn),有興趣的同學(xué)可以了解下具體的實(shí)現(xiàn),例如使用 Socket API 實(shí)現(xiàn)通信的編碼方式,但是大部分實(shí)現(xiàn)接口并不會(huì)在面試中被考察,關(guān)注的重點(diǎn)在于定義。