Linux進(jìn)程間通信10分鐘快速入門

在Linux環(huán)境下運(yùn)行程序赞警,無論是點(diǎn)擊桌面上的一個(gè)圖標(biāo)妓忍,還是在命令行下敲擊一個(gè)shell命令,Linux系統(tǒng)都會(huì)把我們的程序“包裝”成一個(gè)進(jìn)程的形式愧旦,然后調(diào)度運(yùn)行:每個(gè)進(jìn)程輪流占用CPU一段時(shí)間去執(zhí)行世剖,時(shí)間到了就讓給其它進(jìn)程,時(shí)間片輪轉(zhuǎn)忘瓦,只要輪轉(zhuǎn)得速度足夠快搁廓,就會(huì)給用戶一種錯(cuò)覺:我們?cè)陔娔X上一邊聽歌引颈,一邊打字耕皮,感覺多個(gè)程序在同時(shí)運(yùn)行。不同進(jìn)程在運(yùn)行過程中蝙场,根據(jù)業(yè)務(wù)需要凌停,進(jìn)程相互之間也會(huì)通信:比如傳輸數(shù)據(jù)、發(fā)送信號(hào)等售滤。

Linux環(huán)境下的進(jìn)程間通信(Inter-Process Communication罚拟,簡(jiǎn)稱IPC)有多種工具可以使用,如:無名管道pipe完箩、命名管道FIFO赐俗、消息隊(duì)列、共享內(nèi)存弊知、信號(hào)量阻逮、信號(hào)、文件鎖秩彤、socket等叔扼。這些IPC工具以系統(tǒng)調(diào)用或庫函數(shù)API的形式提供給用戶使用:用戶使用這些API可以在不同的進(jìn)程之間傳輸數(shù)據(jù)、同步進(jìn)程漫雷、或者發(fā)送信號(hào)瓜富。比如,我們可以使用ctrl+C組合鍵去終止一個(gè)進(jìn)程降盹,或者使用shell命令kill 3567去殺死一個(gè)進(jìn)程pid為3567的進(jìn)程与柑,這些其實(shí)都是給進(jìn)程發(fā)送信號(hào),進(jìn)程接收信號(hào)并進(jìn)行處理的過程蓄坏。

不同的IPC工具价捧,使用場(chǎng)合不同,各有優(yōu)劣剑辫。為了更好地使用它們干旧,我們不僅要熟練掌握API接口的使用,還要對(duì)它們的通信機(jī)制妹蔽、內(nèi)核實(shí)現(xiàn)原理有一個(gè)大致的了解嫡霞。只有掌握了底層的實(shí)現(xiàn)原理、我們才能明白每個(gè)IPC通信工具的優(yōu)點(diǎn)和缺點(diǎn)采盒、以及他們的使用場(chǎng)合俐巴。想要真正理解Linux進(jìn)程之間到底是如何通信的,首先要搞明白Linux下的不同進(jìn)程在運(yùn)行過程中茉兰,在內(nèi)存中是以什么樣的形態(tài)存在的,以及與Linux內(nèi)核之間是如何交互的。想要理解這點(diǎn)内贮,我們還需要對(duì)Linux環(huán)境下程序的編譯、執(zhí)行過程有一個(gè)大概的了解汞斧。

1 程序的編譯和執(zhí)行

當(dāng)我們?cè)谧烂嫔宵c(diǎn)擊一個(gè)圖標(biāo)夜郁,或者在命令行下敲擊一個(gè)shell命令運(yùn)行時(shí),Linux系統(tǒng)會(huì)把這些可執(zhí)行文件加載到內(nèi)存粘勒,并封裝成一個(gè)進(jìn)程竞端,然后才能參與操作系統(tǒng)的調(diào)度、運(yùn)行庙睡。那操作系統(tǒng)是如何加載的呢事富?

1564654740303.png

首先,我們編寫的C語言源代碼會(huì)編譯成一個(gè)可執(zhí)行文件(ELF)乘陪⊥程ǎ可執(zhí)行文件分由各種不同的段(section)組成:代碼段、數(shù)據(jù)段啡邑、BSS段等贱勃。我們C程序中的不同代碼會(huì)被編譯到不同的段中:函數(shù)實(shí)現(xiàn)會(huì)放到代碼段;全局變量谣拣、靜態(tài)局部變量會(huì)放到數(shù)據(jù)段募寨;未初始化的全局變量會(huì)放到BSS段中......

加載器加載程序到內(nèi)存執(zhí)行,一般分2步走:第一步森缠,會(huì)首先使用fork去創(chuàng)建一個(gè)子進(jìn)程拔鹰,每個(gè)子進(jìn)程有4G的虛擬地址空間。第二步贵涵,從磁盤上軟件安裝的位置列肢,去讀取可執(zhí)行文件的頭部:ELF header,獲取各個(gè)段的信息宾茂,然后分別將不同的段加載到進(jìn)程空間的不同位置瓷马,如上圖所示。

在一個(gè)計(jì)算機(jī)系統(tǒng)中跨晴,通常會(huì)有多個(gè)進(jìn)程同時(shí)運(yùn)行欧聘,每一個(gè)進(jìn)程差不多都是通過上面這種 fork-exec 的方式運(yùn)行的。當(dāng)運(yùn)行的進(jìn)程多了端盆,每個(gè)進(jìn)程都想霸占CPU怀骤、獨(dú)享CPU费封,CPU的資源就不夠用了,這個(gè)時(shí)候操作系統(tǒng)就開始登場(chǎng)了蒋伦。操作系統(tǒng)扮演一個(gè)調(diào)度者的角色弓摘,協(xié)調(diào)各個(gè)進(jìn)程輪流占用CPU運(yùn)行。

1564656367916.png

如上圖所示痕届,對(duì)于用戶運(yùn)行的不同進(jìn)程韧献,在內(nèi)核空間,會(huì)有一個(gè)專門的數(shù)據(jù)結(jié)構(gòu)來表示:task_struct研叫。這個(gè)結(jié)構(gòu)體描述了進(jìn)程的各種信息锤窑,不同的task_sruct結(jié)構(gòu)體通過鏈表串起來,內(nèi)核通過鏈表就可以對(duì)這些進(jìn)程進(jìn)行管理蓝撇。操作系統(tǒng)會(huì)有一個(gè)叫調(diào)度器的核心組件果复,每隔一段時(shí)間(一般是毫秒級(jí))會(huì)有一個(gè)定時(shí)器中斷陈莽,Linux調(diào)度器就會(huì)把正在運(yùn)行的進(jìn)程從CPU上趕下來渤昌,接著讓另一個(gè)進(jìn)程去執(zhí)行,如此反復(fù)走搁,周而復(fù)始独柑。只要CPU的速度足夠快、輪流執(zhí)行的頻率足夠高私植,對(duì)于用戶來說忌栅,就感覺多個(gè)程序同時(shí)運(yùn)行。

2 進(jìn)程的地址空間

每一個(gè)進(jìn)程曲稼,都有一個(gè)4G大小索绪、獨(dú)立的虛擬地址空間,然后通過頁表映射贫悄,映射到物理內(nèi)存的不同位置上瑞驱。CPU執(zhí)行不同的進(jìn)程時(shí),根據(jù)每個(gè)進(jìn)程的映射頁表窄坦,就會(huì)到其對(duì)應(yīng)的物理內(nèi)存上一條一條地取指令唤反、翻譯指令、運(yùn)行指令鸭津。

1564656641206.png

如上圖中的進(jìn)程A和進(jìn)程B彤侍,它們?cè)趦?nèi)存中有相同的4G虛擬地址空間,但是每個(gè)進(jìn)程通過各自的頁表映射逆趋,就映射到了物理內(nèi)存中的不同位置盏阶。也就是說,每個(gè)進(jìn)程的虛擬地址空間雖然是相同的闻书,但是它們?cè)谖锢韮?nèi)存空間上卻是相同隔離的名斟、相互獨(dú)立的吴汪。在每個(gè)進(jìn)程的4G虛擬地址空間中,[0蒸眠,3G]這段地址空間是每個(gè)進(jìn)程獨(dú)有的漾橙,而[3G,4G]這段空間是被內(nèi)核占用的,不同進(jìn)程的[3G,4G]這段空間都被內(nèi)核占用楞卡。內(nèi)核本身在運(yùn)行時(shí)霜运,在物理內(nèi)存上也會(huì)有自己?jiǎn)为?dú)的存儲(chǔ)空間。

1564657079518.png

3 Linux進(jìn)程間通信的三種方法

通過上面的學(xué)習(xí)我們可以看到蒋腮,用戶空間的不同進(jìn)程淘捡,它們?cè)跁r(shí)空上是相互隔離、相互獨(dú)立的池摧,如同黑夜和白天焦除,太陽和月亮,永遠(yuǎn)不會(huì)見面作彤,老死不相往來膘魄。但萬事沒有絕對(duì),各個(gè)進(jìn)程之間如果真想通信竭讳,還是有方法的创葡,如下圖所示。

1564658539689.png

用戶空間的每個(gè)進(jìn)程雖說在物理內(nèi)存空間上是相互隔離绢慢、相互獨(dú)立的灿渴,但通過內(nèi)核空間這一共享區(qū)域,它們還是可以相互通信的胰舆。只要內(nèi)核愿意骚露、提供一些空間,不同的進(jìn)程之間就可以對(duì)這塊內(nèi)存空間讀寫數(shù)據(jù)缚窿,達(dá)到進(jìn)程間通信的目的棘幸。磁盤也是公共存儲(chǔ)空間,不同進(jìn)程也可以通過往磁盤上某個(gè)指定的文件讀寫數(shù)據(jù)完成進(jìn)程間的通信滨攻。除此之外够话,不同的進(jìn)程之間,如果事先商量好光绕,也可以繞過內(nèi)核女嘲,通過內(nèi)存映射,在物理內(nèi)存上建立一片共享內(nèi)存诞帐,直接進(jìn)行通信欣尼。

4 無名管道pipe通信機(jī)制

以Linux的無名管道pipe通信機(jī)制為例:無名管道常用于有血緣關(guān)系的進(jìn)程之間的通信,我們可以通過pipe系統(tǒng)調(diào)用去創(chuàng)建一個(gè)管道:

int pipe (int  pipefd[2]);

該函數(shù)會(huì)創(chuàng)建一個(gè)管道,這個(gè)管道有兩個(gè)文件描述符愕鼓,一個(gè)用來讀钙态,一個(gè)用來寫,不同進(jìn)程可以通過讀寫描述符對(duì)這個(gè)管道進(jìn)行讀寫菇晃,達(dá)到進(jìn)程間通信的目的册倒。

1564660602383.png

無名管道在內(nèi)核中的實(shí)現(xiàn)其實(shí)很簡(jiǎn)單,就是Linux內(nèi)核空間的一片緩沖區(qū)磺送,通過pipefs機(jī)制把它封裝成一個(gè)文件的形式驻子,留出文件的讀寫接口:文件描述符給用戶空間進(jìn)程。用戶空間的不同進(jìn)程通過這一對(duì)讀寫描述符就可以對(duì)管道進(jìn)行讀寫估灿。

1564660740725.png

5 更多的進(jìn)程間通信工具

除了無名管道外崇呵,Linux提供了很多進(jìn)程間通信的工具可以使用,比如:命名管道FIFO馅袁、信號(hào)量域慷、消息隊(duì)列、共享內(nèi)存汗销、信號(hào)signal犹褒、socket、Dbus等大溜。不同的IPC工具有各自的優(yōu)缺點(diǎn)化漆、使用場(chǎng)合。比如無名管道只能用于親緣關(guān)系的進(jìn)程間通信钦奋,命名管道PIPE解決了這一局限,支持任意兩進(jìn)程之間的通信疙赠;消息隊(duì)列可以支持有數(shù)據(jù)格式的通信付材,共享內(nèi)存效率最高,但是需要跟信號(hào)量圃阳、鎖等同步機(jī)制結(jié)合使用厌衔;信號(hào)主要用于進(jìn)程間的異步通信,也是唯一的一種異步通信機(jī)制捍岳。

每一種IPC通信工具富寿,都有自己的優(yōu)缺點(diǎn)、使用場(chǎng)合和局限锣夹,我們只有全面了解和掌握各個(gè)IPC工具的使用页徐,知曉其優(yōu)缺點(diǎn),才能在實(shí)際的工作中根據(jù)需要银萍,選擇合適的通信機(jī)制变勇。除了這些POSIX/system V標(biāo)準(zhǔn)接口定義的IPC工具外,Linux系統(tǒng)還擴(kuò)展了一些自己獨(dú)特的API贴唇,如signalfd搀绣、timerfd等飞袋,解決了信號(hào)通信機(jī)制的一些缺陷。想要進(jìn)一步了解這些IPC工具接口的使用和實(shí)現(xiàn)機(jī)制链患,可以關(guān)注教程:《Linux系統(tǒng)編程》第05期:進(jìn)程間通信巧鸭,目前已經(jīng)錄制完畢,已在各大平臺(tái)陸續(xù)上傳麻捻,已經(jīng)通過淘寶預(yù)售購買的同學(xué)可以直接下載學(xué)習(xí)了:淘寶店蹄皱。

image
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市芯肤,隨后出現(xiàn)的幾起案子巷折,更是在濱河造成了極大的恐慌,老刑警劉巖崖咨,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锻拘,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡击蹲,警方通過查閱死者的電腦和手機(jī)署拟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來歌豺,“玉大人推穷,你說我怎么就攤上這事±噙郑” “怎么了馒铃?”我有些...
    開封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)痕惋。 經(jīng)常有香客問我区宇,道長(zhǎng),這世上最難降的妖魔是什么值戳? 我笑而不...
    開封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任议谷,我火速辦了婚禮,結(jié)果婚禮上堕虹,老公的妹妹穿的比我還像新娘卧晓。我一直安慰自己,他們只是感情好赴捞,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開白布逼裆。 她就那樣靜靜地躺著,像睡著了一般螟炫。 火紅的嫁衣襯著肌膚如雪波附。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音掸屡,去河邊找鬼封寞。 笑死,一個(gè)胖子當(dāng)著我的面吹牛仅财,可吹牛的內(nèi)容都是我干的狈究。 我是一名探鬼主播,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼盏求,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼抖锥!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起碎罚,我...
    開封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤磅废,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后荆烈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拯勉,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年憔购,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了宫峦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡玫鸟,死狀恐怖导绷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情屎飘,我是刑警寧澤妥曲,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站枚碗,受9級(jí)特大地震影響逾一,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜肮雨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望箱玷。 院中可真熱鬧怨规,春花似錦、人聲如沸锡足。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽舶得。三九已至掰烟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背纫骑。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來泰國打工蝎亚, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人先馆。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓发框,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親煤墙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子梅惯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容