進(jìn)程間通信
引言
在操作系統(tǒng)中,一個(gè)進(jìn)程可以理解為是關(guān)于計(jì)算機(jī)資源集合的一次運(yùn)行活動(dòng)已烤,其就是一個(gè)正在執(zhí)行的程序的實(shí)例。從概念上來(lái)說(shuō),一個(gè)進(jìn)程擁有它自己的虛擬CPU和虛擬地址空間际邻,任何一個(gè)進(jìn)程對(duì)于彼此而言都是相互獨(dú)立的,這也引入了一個(gè)問題 —— 如何讓進(jìn)程之間互相通信芍阎?
由于進(jìn)程之間是互相獨(dú)立的世曾,沒有任何手段直接通信,因此我們需要借助操作系統(tǒng)來(lái)輔助它們谴咸。舉個(gè)通俗的例子度硝,假如A與B之間是獨(dú)立的,不能彼此聯(lián)系寿冕,如果它們想要通信的話可以借助第三方C蕊程,比如A將信息交給C,C再將信息轉(zhuǎn)交給B —— 這就是進(jìn)程間通信的主要思想 —— 共享資源驼唱。
這里要解決的一個(gè)重要的問題就是如何避免競(jìng)爭(zhēng)藻茂,即避免多個(gè)進(jìn)程同時(shí)訪問臨界區(qū)的資源。
共享內(nèi)存
共享內(nèi)存是進(jìn)程間通信中最簡(jiǎn)單的方式之一玫恳。共享內(nèi)存允許兩個(gè)或更多進(jìn)程訪問同一塊內(nèi)存辨赐。當(dāng)一個(gè)進(jìn)程改變了這塊地址中的內(nèi)容的時(shí)候,其它進(jìn)程都會(huì)察覺到這個(gè)更改京办。
你可能會(huì)想到掀序,我直接創(chuàng)建一個(gè)文件,然后進(jìn)程不就都可以訪問了惭婿?
是的不恭,但這個(gè)方法有幾個(gè)缺陷:
- 訪問文件需要陷入系統(tǒng)調(diào)用叶雹,由用戶態(tài)切入內(nèi)核態(tài),然后執(zhí)行內(nèi)核指令换吧。這樣做效率是非常低的折晦,并且是不受用戶掌握的。
- 直接訪問磁盤是非常慢的沾瓦,比訪問內(nèi)存要慢上幾百倍满着。從某種意義上說(shuō),這是共享磁盤不算共享內(nèi)存贯莺。
Linux下采用共享內(nèi)存的方式來(lái)使進(jìn)程完成對(duì)共享資源的訪問风喇,它將磁盤文件復(fù)制到內(nèi)存,并創(chuàng)建虛擬地址到該內(nèi)存的映射缕探,就好像該資源本來(lái)就在進(jìn)程空間之中响驴,此后我們就可以像操作本地變量一樣去操作它們了,實(shí)際的寫入磁盤將由系統(tǒng)選擇最佳方式完成撕蔼,例如操作系統(tǒng)可能會(huì)批量處理加排序豁鲤,從而大大提高IO速度。
如同上圖一樣鲸沮,進(jìn)程將共享內(nèi)存映射到自己的虛擬地址空間中琳骡,進(jìn)程訪問共享進(jìn)程就好像在訪問自己的虛擬內(nèi)存一樣,速度是非乘夏纾快的楣号。
共享內(nèi)存的模型應(yīng)該是比較好理解的:在物理內(nèi)存中創(chuàng)建一個(gè)共享資源文件,進(jìn)程將該共享內(nèi)存綁定到自己的虛擬內(nèi)存之中怒坯。
這里要解決的一個(gè)問題是如何將同一塊共享內(nèi)存綁定到自己的虛擬內(nèi)存中炫狱,要知道在不同進(jìn)程中使用malloc
函數(shù)是會(huì)順序分配空閑內(nèi)存,而不會(huì)分配同一塊內(nèi)存剔猿,那么要如何去解決這個(gè)問題呢视译?
Linux操作系統(tǒng)已經(jīng)想辦法幫我們解決了這個(gè)問題,在#include <sys/ipc.h>
和#include <sys/shm.h>
頭文件下归敬,有如下幾個(gè)shm系列函數(shù):
-
shmget函數(shù):由ftok()函數(shù)獲取需要共享文件資源標(biāo)識(shí)符(IPC鍵)酷含,將該資源標(biāo)識(shí)符作為參數(shù)獲取共享內(nèi)存區(qū)域的唯一標(biāo)識(shí)ID。
ftok()函數(shù)用以標(biāo)識(shí)系統(tǒng)IPC資源汪茧,例如這里的共享資源椅亚、下文的消息隊(duì)列、管道......都屬于IPC資源舱污。
IPC(Inter-Process[ Communication](https://baike.baidu.com/item/ Communication/20394231)呀舔,進(jìn)程間通信),IPC是指兩個(gè)進(jìn)程的數(shù)據(jù)之間產(chǎn)生交互扩灯。
shmat函數(shù):通過(guò)由shmget函數(shù)獲取的標(biāo)識(shí)符媚赖,建立由共享內(nèi)存到進(jìn)程獨(dú)立空間的映射霜瘪。
shmdt函數(shù):釋放映射。
計(jì)算機(jī)界有一句名言:如果平時(shí)不經(jīng)常使用某個(gè)函數(shù)工作的話省古,記住這些函數(shù)復(fù)雜的參數(shù)以及使用方法是沒有太大意義的,學(xué)習(xí)是需要注重函數(shù)用途以及原理丧失。
由于我們主要走Java/Go開發(fā)崗位豺妓,我們與這些Linux系統(tǒng)下的C函數(shù)打交道的次數(shù)可能為0,因此在學(xué)習(xí)中我不會(huì)詳細(xì)的描述函數(shù)的具體使用方法布讹,當(dāng)我們用上時(shí)Bing搜索即可琳拭。
通過(guò)上述幾個(gè)函數(shù),每個(gè)獨(dú)立的進(jìn)程只要有統(tǒng)一的共享內(nèi)存標(biāo)識(shí)符便可以建立起虛擬地址到物理地址的映射描验,每個(gè)虛擬地址將被翻譯成指向共享區(qū)域的物理地址白嘁,這樣就實(shí)現(xiàn)了對(duì)共享內(nèi)存的訪問。
還有一種相像的實(shí)現(xiàn)是采用mmap函數(shù)膘流,mmap通常是直接對(duì)磁盤的映射——因此不算是共享內(nèi)存絮缅,存儲(chǔ)量非常大,但訪問慢呼股;shmat與此相反耕魄,通常將資源保存在內(nèi)存中創(chuàng)建映射,訪問快彭谁,但存儲(chǔ)量較小吸奴。
不過(guò)要注意一點(diǎn),操作系統(tǒng)并不保證任何并發(fā)問題缠局,例如兩個(gè)進(jìn)程同時(shí)更改同一塊內(nèi)存區(qū)域则奥,正如你和你的朋友在線編輯同一個(gè)文檔中的同一個(gè)標(biāo)題,這會(huì)導(dǎo)致一些不好的結(jié)果狭园,所以我們需要借助信號(hào)量或其他方式來(lái)完成同步读处。
信號(hào)量
信號(hào)量是迪杰斯特拉最先提出的一種為解決同步不同執(zhí)行線程問題
的一種方法,進(jìn)程與線程抽象來(lái)看大同小異唱矛,所以信號(hào)量同樣可以用于同步進(jìn)程間通信档泽。
信號(hào)量的工作原理
信號(hào)量 s 是具有非負(fù)整數(shù)值的全局變量,由兩種特殊的原子操作來(lái)實(shí)現(xiàn)揖赴,這兩種原子操作稱為 P 和 V :
P(s):如果 s 的值大于零馆匿,就給它減1,然后立即返回燥滑,進(jìn)程繼續(xù)執(zhí)行渐北。;如果它的值為零铭拧,就掛起該進(jìn)程的執(zhí)行赃蛛,等待 s 重新變?yōu)榉橇阒怠?/p>
V(s):V操作將 s 的值加1恃锉,如果有任何進(jìn)程在等在 s 值變?yōu)榉?,那么V操作會(huì)重啟這些等待進(jìn)程中的其中一個(gè)(隨機(jī)地)呕臂,然后由該進(jìn)程執(zhí)行P操作將 s 重新置為0鸳吸,而其他等待進(jìn)程將會(huì)繼續(xù)等待斤寂。
理解信號(hào)量
信號(hào)量并不用來(lái)傳送資源,而是用來(lái)保護(hù)共享資源,理解這一點(diǎn)是很重要的积担,信號(hào)量 s 的表示的含義為同時(shí)允許最大訪問資源的進(jìn)程數(shù)量锨阿,它是一個(gè)全局變量恳不。來(lái)考慮一個(gè)上面簡(jiǎn)單的例子:兩個(gè)進(jìn)程同時(shí)修改而造成錯(cuò)誤望忆,我們不考慮讀者而僅僅考慮寫者進(jìn)程,在這個(gè)例子中共享資源最多允許一個(gè)進(jìn)程修改資源阐虚,因此我們初始化 s 為1序臂。
開始時(shí),A率先寫入資源实束,此時(shí)A調(diào)用P(s)奥秆,將 s 減一,此時(shí) s = 0咸灿,A進(jìn)入共享區(qū)工作吭练。
此時(shí),進(jìn)程B也想進(jìn)入共享區(qū)修改資源析显,它調(diào)用P(s)發(fā)現(xiàn)此時(shí)s為0鲫咽,于是掛起進(jìn)程,加入等待隊(duì)列谷异。
A工作完畢分尸,調(diào)用V(s),它發(fā)現(xiàn)s為0并檢測(cè)到等待隊(duì)列不為空歹嘹,于是它隨機(jī)喚醒一個(gè)等待進(jìn)程箩绍,并將s加1,這里喚醒了B尺上。
B被喚醒材蛛,繼續(xù)執(zhí)行P操作,此時(shí)s不為0怎抛,B成功執(zhí)行將s置為0并進(jìn)入工作區(qū)卑吭。
此時(shí)C想要進(jìn)入工作區(qū)......
可以發(fā)現(xiàn),在無(wú)論何時(shí)只有一個(gè)進(jìn)程能夠訪問共享資源马绝,這就是信號(hào)量做的事情豆赏,他控制進(jìn)入共享區(qū)的最大進(jìn)程數(shù)量,這取決于初始化s的值。此后掷邦,在進(jìn)入共享區(qū)之前調(diào)用P操作白胀,出共享區(qū)后調(diào)用V操作,這就是信號(hào)量的思想抚岗。
在Linux下并沒有直接的P&V函數(shù)或杠,而是需要我們根據(jù)這幾個(gè)基本的sem函數(shù)族進(jìn)行封裝:
- semget:初始化或獲取一個(gè)信號(hào)量,這個(gè)函數(shù)需要接受ftok()的返回值以及初始s的值宣蔚,它將全局計(jì)數(shù)變量s綁定在由ftok標(biāo)識(shí)的共享資源上向抢,并返回一個(gè)唯一標(biāo)識(shí)的信號(hào)量組ID。
- semop:這個(gè)函數(shù)接受上面函數(shù)返回的信號(hào)量組ID以及一些其他參數(shù)件已,根據(jù)參數(shù)的不同有一些不同的操作笋额,他將對(duì)與該信號(hào)量組ID綁定的全局計(jì)數(shù)變量 s 進(jìn)行一些操作元暴,P&V操作便是基于此實(shí)現(xiàn)篷扩。
- semctl:這個(gè)函數(shù)接受上面函數(shù)返回的信號(hào)量組ID以及一些其他參數(shù),主要進(jìn)行控制信號(hào)量相關(guān)信息茉盏,如刪除該信號(hào)量等鉴未。
管道
正如其名,管道就如同生活中的一根管道鸠姨,一端輸送铜秆,而另一端接收,雙方不需要知道對(duì)方讶迁,只需要知道管道就好了连茧。
管道是一種最基本的進(jìn)程間通信機(jī)制。 管道由pipe函數(shù)來(lái)創(chuàng)建: 調(diào)用pipe函數(shù)巍糯,會(huì)在內(nèi)核中開辟出一塊緩沖區(qū)用來(lái)進(jìn)行進(jìn)程間通信啸驯,這塊緩沖區(qū)稱為管道,它有一個(gè)讀端和一個(gè)寫端祟峦。管道被分為匿名管道和有名管道罚斗。
匿名管道
匿名管道通過(guò)pipe函數(shù)創(chuàng)建,這個(gè)函數(shù)接收一個(gè)長(zhǎng)度為2的Int數(shù)組宅楞,并返回1或0表示成功或者失斦胱恕:
int pipe(int fd[2])
這個(gè)函數(shù)打開兩個(gè)文件描述符,一個(gè)讀端文件厌衙,一個(gè)寫端距淫,分別存入fd[0]和fd[1]中,然后可以作為參數(shù)調(diào)用write
和read
函數(shù)進(jìn)行寫入或讀取婶希,注意fd[0]只能讀取文件溉愁,而fd[1]只能用于寫入文件。
你可能有個(gè)疑問,這要怎么實(shí)現(xiàn)通信拐揭?其他進(jìn)程又不知道這個(gè)管道撤蟆,因?yàn)檫M(jìn)程是獨(dú)立的,其他進(jìn)程看不到某一個(gè)進(jìn)程進(jìn)行了什么操作堂污。
是的家肯,‘其他’進(jìn)程確實(shí)是不知道,但是它的子進(jìn)程卻可以盟猖!這里涉及到fork派生進(jìn)程的相關(guān)知識(shí)讨衣,一個(gè)進(jìn)程派生一個(gè)子進(jìn)程,那么子進(jìn)程將會(huì)復(fù)制父進(jìn)程的內(nèi)存空間信息式镐,注意這里是復(fù)制而不是共享反镇,這意味著父子進(jìn)程仍然是獨(dú)立的,但是在這一時(shí)刻娘汞,它們所有的信息又是相等的歹茶。因此子進(jìn)程也知道該全局管道,并且也擁有兩個(gè)文件描述符與管道掛鉤你弦,所以匿名管道只能在具有親緣關(guān)系的進(jìn)程間通信惊豺。
還要注意,匿名管道內(nèi)部采用環(huán)形隊(duì)列實(shí)現(xiàn)禽作,只能由寫端到讀端尸昧,由于設(shè)計(jì)技術(shù)問題,管道被設(shè)計(jì)為半雙工的旷偿,一方要寫入則必須關(guān)閉讀描述符烹俗,一方要讀出則必須關(guān)閉寫入描述符。因此我們說(shuō)管道的消息只能單向傳遞萍程。
注意管道是堵塞的幢妄,如何堵塞將依賴于讀寫進(jìn)程是否關(guān)閉文件描述符。如果讀管道尘喝,如果讀到空時(shí)磁浇,假設(shè)此時(shí)寫端口還沒有被完全關(guān)閉,那么操作系統(tǒng)會(huì)假設(shè)還有數(shù)據(jù)要讀朽褪,此時(shí)讀進(jìn)程將會(huì)被堵塞置吓,直到有新數(shù)據(jù)或?qū)懚丝诒魂P(guān)閉;如果管道為空缔赠,且寫端口也被關(guān)閉衍锚,此時(shí)操作系統(tǒng)會(huì)認(rèn)為已經(jīng)沒有東西可讀,會(huì)直接退出嗤堰,并關(guān)閉管道戴质。
對(duì)于寫一個(gè)已經(jīng)滿了的管道同理而言。
管道內(nèi)部由內(nèi)核管理,在半雙工的條件下告匠,保證數(shù)據(jù)不會(huì)出現(xiàn)并發(fā)問題戈抄。
命名管道
了解了匿名管道之后,有名管道便很好理解了后专。在匿名管道的介紹中划鸽,我們說(shuō)其他進(jìn)程不知道管道和文件描述符的存在,所以匿名管道只適用于具有親緣關(guān)系的進(jìn)程戚哎,而命名管道則很好的解決了這個(gè)問題 —— 現(xiàn)在管道有一個(gè)唯一的名稱了裸诽,任何進(jìn)程都可以訪問這個(gè)管道。
注意型凳,操作系統(tǒng)將管道看作一個(gè)抽象的文件丈冬,但管道并不是普通的文件,管道存在于內(nèi)核空間中而不放置在磁盤(有名管道文件系統(tǒng)上有一個(gè)標(biāo)識(shí)符甘畅,沒有數(shù)據(jù)塊)埂蕊,訪問速度更快,但存儲(chǔ)量較小橄浓,管道是臨時(shí)的粒梦,是隨進(jìn)程的亮航,當(dāng)進(jìn)程銷毀荸实,所有端口自動(dòng)關(guān)閉,此時(shí)管道也是不存在的缴淋,操作系統(tǒng)將所有IO抽象的看作文件准给,例如網(wǎng)絡(luò)也是一種文件,這意味著我們可以采用任何文件方法操作管道重抖,理解這種抽象是很重要的露氮,命名管道就利用了這種抽象。
Linux下钟沛,采用mkfifo函數(shù)創(chuàng)建畔规,可以傳入要指定的‘文件名’,然后其他進(jìn)程就可以調(diào)用open方法打開這個(gè)特殊的文件恨统,并進(jìn)行write和read操作(那肯定是字節(jié)流對(duì)吧)叁扫。
注意,命名管道適用于任何進(jìn)程畜埋,除了這一點(diǎn)不同外莫绣,其余大多數(shù)都與匿名管道相同。
消息隊(duì)列
什么是消息隊(duì)列悠鞍?
消息隊(duì)列亦稱報(bào)文隊(duì)列对室,也叫做信箱,是Linux的一種通信機(jī)制,這種通信機(jī)制傳遞的數(shù)據(jù)會(huì)被拆分為一個(gè)一個(gè)獨(dú)立的數(shù)據(jù)塊掩宜,也叫做消息體蔫骂,消息體中可以定義類型與數(shù)據(jù),克服了無(wú)格式承載字節(jié)流的缺陷(現(xiàn)在收到void*后可以知道其原本的格式惹):
struct msgbuf {
long mtype; /* 消息的類型 */
char mtext[1]; /* 消息正文 */
};
同管道類似牺汤,它有一個(gè)不足就是每個(gè)消息的最大長(zhǎng)度是有上限的纠吴,整個(gè)消息隊(duì)列也是長(zhǎng)度限制的。
內(nèi)核為每個(gè)IPC對(duì)象維護(hù)了一個(gè)數(shù)據(jù)結(jié)構(gòu)struct ipc_perm慧瘤,該數(shù)據(jù)結(jié)構(gòu)中有指向鏈表頭與鏈表尾部的指針戴已,保證每一次插入取出都是O(1)的時(shí)間復(fù)雜度。
1. msgget
功能:創(chuàng)建或訪問一個(gè)消息隊(duì)列
原型:
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgget(key_t key, int msgflag);
參數(shù):
key:某個(gè)消息隊(duì)列的名字锅减,用ftok()產(chǎn)生糖儡,消息隊(duì)列為PIC資源,該key標(biāo)識(shí)了此消息隊(duì)列怔匣,如果傳入key存在握联,則返回對(duì)應(yīng)消息隊(duì)列ID,否則每瞒,創(chuàng)建并返回消息隊(duì)列ID金闽。
msgflag:有兩個(gè)選項(xiàng)IPC_CREAT和IPC_EXCL,單獨(dú)使用IPC_CREAT剿骨,如果消息隊(duì)列不存在則創(chuàng)建之代芜,如果存在則打開返回;單獨(dú)使用IPC_EXCL是沒有意義的浓利;兩個(gè)同時(shí)使用挤庇,如果消息隊(duì)列不存在則創(chuàng)建之,如果存在則出錯(cuò)返回贷掖。返回值:成功返回一個(gè)非負(fù)整數(shù)嫡秕,即消息隊(duì)列的標(biāo)識(shí)碼,失敗返回-1
2. msgctl
功能:消息隊(duì)列的控制函數(shù)原型:
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgctl(int msqid, int cmd, struct msqid_ds *buf);
參數(shù):
msqid:由msgget函數(shù)返回的消息隊(duì)列標(biāo)識(shí)碼
cmd:有三個(gè)可選的值苹威,在此我們使用IPC_RMID
- IPC_STAT 把msqid_ds結(jié)構(gòu)中的數(shù)據(jù)設(shè)置為消息隊(duì)列的當(dāng)前關(guān)聯(lián)值
- IPC_SET 在進(jìn)程有足夠權(quán)限的前提下昆咽,把消息隊(duì)列的當(dāng)前關(guān)聯(lián)值設(shè)置為msqid_ds數(shù)據(jù)結(jié)構(gòu)中給出的值
- IPC_RMID 刪除消息隊(duì)列
返回值:
成功返回0,失敗返回-13. msgsnd
功能:把一條消息添加到消息隊(duì)列中原型:
#include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
參數(shù):
msgid:由msgget函數(shù)返回的消息隊(duì)列標(biāo)識(shí)碼
msgp:指針指向準(zhǔn)備發(fā)送的消息
msgze:msgp指向的消息的長(zhǎng)度(不包括消息類型的long int長(zhǎng)整型)
msgflg:默認(rèn)為0返回值:成功返回0牙甫,失敗返回-1
4. msgrcv
功能:是從一個(gè)消息隊(duì)列接受消息原型:
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);參數(shù):與msgsnd相同
返回值:成功返回實(shí)際放到接收緩沖區(qū)里去的字符個(gè)數(shù)掷酗,失敗返回-1
特點(diǎn)
- 與管道不同,消息隊(duì)列的生命周期隨內(nèi)核腹暖,不會(huì)隨進(jìn)程銷毀而銷毀汇在,需要我們顯示的調(diào)用接口刪除或使用命令刪除。
- 消息隊(duì)列可以雙向通信脏答。
- 克服了管道只能承載無(wú)格式字節(jié)流的缺點(diǎn)糕殉。
信號(hào)
關(guān)于信號(hào)
一個(gè)進(jìn)程可以發(fā)送信號(hào)給另一個(gè)進(jìn)程亩鬼,一個(gè)信號(hào)就是一條消息,可以用于通知一個(gè)進(jìn)程組發(fā)送了某種類型的事件阿蝶,該進(jìn)程組中的進(jìn)程可以采取處理程序處理事件雳锋。
Linux下unistd.h
頭文件下定義了如圖中的常量,當(dāng)你在shell命令行鍵入ctrl + c
時(shí)羡洁,內(nèi)核就會(huì)前臺(tái)進(jìn)程組的每一個(gè)進(jìn)程發(fā)送SIGINT
信號(hào)玷过,中止進(jìn)程。
我們可以看到上述只有30個(gè)信號(hào)筑煮,因此操作系統(tǒng)會(huì)為每一個(gè)進(jìn)程維護(hù)一個(gè)int類型變量sig辛蚊,利用其中30位代表是否有對(duì)應(yīng)信號(hào)事件,每一個(gè)進(jìn)程還有一個(gè)int類型變量block真仲,與sig對(duì)應(yīng)袋马,其30位表示是否堵塞對(duì)應(yīng)信號(hào)(不調(diào)用處理程序)。如果存在多個(gè)相同的信號(hào)同時(shí)到來(lái)秸应,多余信號(hào)會(huì)被存儲(chǔ)在一個(gè)等待隊(duì)列中等待虑凛。
我們要理解進(jìn)程組是什么,每個(gè)進(jìn)程屬于一個(gè)進(jìn)程組软啼,可以有多個(gè)進(jìn)程屬于同一個(gè)組桑谍。每個(gè)進(jìn)程擁有一個(gè)進(jìn)程ID,稱為pid
祸挪,而每個(gè)進(jìn)程組擁有一個(gè)進(jìn)程組ID锣披,稱為pgid
,默認(rèn)情況下匕积,一個(gè)進(jìn)程與其子進(jìn)程屬于同一進(jìn)程組盈罐。
軟件方面(諸如檢測(cè)鍵盤輸入是硬件方面)可以利用kill函數(shù)發(fā)送信號(hào)榜跌,kill函數(shù)接受兩個(gè)參數(shù)闪唆,進(jìn)程ID和信號(hào)類型,它將該信號(hào)類型發(fā)送到對(duì)應(yīng)進(jìn)程钓葫,如果該pid為0悄蕾,那么會(huì)發(fā)送到屬于自身進(jìn)程組的所有進(jìn)程。
接收方可以采用signal函數(shù)給對(duì)應(yīng)事件添加處理程序础浮,一旦事件發(fā)生帆调,如果未被堵塞,則調(diào)用該處理程序豆同。
Linux下有一套完善的函數(shù)用以處理信號(hào)機(jī)制番刊。
特點(diǎn)
- 信號(hào)是在軟件層次上對(duì)中斷機(jī)制的一種模擬,是一種異步通信方式影锈。
- 信號(hào)可以直接進(jìn)行用戶空間進(jìn)程和內(nèi)核進(jìn)程之間的交互芹务,內(nèi)核進(jìn)程也可以利用它來(lái)通知用戶空間進(jìn)程發(fā)生了哪些系統(tǒng)事件蝉绷。
- 如果該進(jìn)程當(dāng)前并未處于執(zhí)行態(tài),則該信號(hào)就由內(nèi)核保存起來(lái)枣抱,直到該進(jìn)程恢復(fù)執(zhí)行再傳遞給它熔吗;如果一個(gè)信號(hào)被進(jìn)程設(shè)置為阻塞,則該信號(hào)的傳遞被延遲佳晶,直到其阻塞被取消時(shí)才被傳遞給進(jìn)程桅狠。
- 信號(hào)有明確生命周期,首先產(chǎn)生信號(hào)轿秧,然后內(nèi)核存儲(chǔ)信號(hào)直到可以發(fā)送它中跌,最后內(nèi)核一旦有空閑,會(huì)適當(dāng)處理信號(hào)菇篡。
- 處理程序是可以被另一個(gè)處理程序中斷的晒他,因此這可能造成并發(fā)問題,所以在處理程序中的代碼應(yīng)該是線程安全的逸贾,通常通過(guò)設(shè)置block位圖以堵塞所有信號(hào)陨仅。
套接字
Socket套接字是用與網(wǎng)絡(luò)中不同主機(jī)的通信方式,多用于客戶端與服務(wù)器之間铝侵,在Linux下也有一系列C語(yǔ)言函數(shù)灼伤,諸如socket、connect咪鲜、bind狐赡、listen與accept,我們無(wú)需花太多時(shí)間研究這些函數(shù)疟丙,因?yàn)槲覀兛赡芤惠呑佣疾粫?huì)與他們打交道颖侄,對(duì)于原理的學(xué)習(xí),后續(xù)我會(huì)對(duì)Java中的套接字socket源碼進(jìn)行剖析享郊。
結(jié)語(yǔ)
對(duì)于工作而言览祖,我們可能一輩子都用不上這些操作,但作為對(duì)于操作系統(tǒng)的學(xué)習(xí)炊琉,認(rèn)識(shí)到進(jìn)程間是如何通信還是很有必要的展蒂。
面試的時(shí)候?qū)τ谶@些方法我們不需要掌握到很深的程度,但我們必須要講的來(lái)有什么通信方式苔咪,這些方式都有什么特點(diǎn)锰悼,適用于什么條件,大致是如何操作的团赏,能說(shuō)出這些箕般,基本足以讓面試官對(duì)你十分滿意了。