新聞中心
Linux操作系統(tǒng)是一個(gè)非常強(qiáng)大的操作系統(tǒng),它具有非常多的優(yōu)秀特性和功能。其中,多進(jìn)程間sem是Linux操作系統(tǒng)的一個(gè)重要功能。本文將討論。

創(chuàng)新互聯(lián)建站是專業(yè)的信州網(wǎng)站建設(shè)公司,信州接單;提供成都做網(wǎng)站、成都網(wǎng)站制作,網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行信州網(wǎng)站開發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!
一、sem的定義
sem是LINUX內(nèi)核中的一種基本信號(hào)量,用于進(jìn)程之間進(jìn)行同步和互斥的工具。Linux操作系統(tǒng)中用信號(hào)量來(lái)實(shí)現(xiàn)進(jìn)程間的同步互斥,sem是一種抽象數(shù)據(jù)類型,表示一組計(jì)數(shù)器,使用時(shí)通過(guò)系統(tǒng)調(diào)用操作sem,它提供了兩種基本操作:P(sv)和V(sv),用于請(qǐng)求和釋放資源、鎖定和解鎖。
二、sem的組成
期中,sem定義如下:
struct sem{
int semval; //semaphore value
int sempid; //PID of the last process that performed a semaphore
key_t semkey; //unique key by which a semaphore is referred
};
sem由下列5個(gè)部分組成:
1、semaphore value,代表著信號(hào)量的值,表示當(dāng)前可用的資源的數(shù)量;
2、last process semaphore pid,最近一次操作信號(hào)量的進(jìn)程的pid,是原子變量,用以保證多個(gè)進(jìn)程訪問(wèn)sem的正確性;
3、unique key,唯一標(biāo)識(shí)sem的符號(hào)名;
4、adjustment,sem的調(diào)整量,P操作的參數(shù);
5、wt queue,信號(hào)量的等待隊(duì)列,當(dāng)信號(hào)量未滿足P操作要求時(shí),要掛起在等待隊(duì)列上,V操作釋放資源后會(huì)喚醒等待在等待隊(duì)列上的進(jìn)程。
三、sem的使用
在Linux中,可以通過(guò)semget()函數(shù)獲取信號(hào)量,它的定義如下:
#include
#include
#include
typedef int semid_t;
extern semid_t semget(key_t key, int num, int flags);
主要有以下參數(shù):
key:標(biāo)識(shí)著信號(hào)量的關(guān)鍵字,可以唯一標(biāo)志一個(gè)信號(hào)量;
num:表示要?jiǎng)?chuàng)建的信號(hào)量的數(shù)目;
flags:是一個(gè)選項(xiàng)參數(shù),可以指定創(chuàng)建新的信號(hào)量,還是獲取已經(jīng)存在的信號(hào)量。
通過(guò)semget()函數(shù)獲取到信號(hào)量的標(biāo)志符后,可以使用semctl()系統(tǒng)調(diào)用函數(shù)對(duì)信號(hào)量進(jìn)行操作,semctl()的定義如下:
extern int semctl(int semid, int num, int cmd,union semun arg);
其中,參數(shù)semid是由semget()函數(shù)返回的信號(hào)量標(biāo)志符,參數(shù)cmd是要執(zhí)行的操作,參數(shù)arg是一個(gè)共用體類型的指針,它根據(jù)cmd來(lái)進(jìn)行不同的操作。semctl()函數(shù)的主要操作如下:
1、SETVAL:用來(lái)初始化信號(hào)量的值;
2、GETVAL:用來(lái)獲取信號(hào)量的值;
3、IPC_RMID:用來(lái)刪除信號(hào)量。
由于sem存在于內(nèi)核中,操作sem的系統(tǒng)調(diào)用影響效率,因此,針對(duì)不同應(yīng)用場(chǎng)景可通過(guò)不同的操作模式盡量減小對(duì)sem的操作。
四、sem在進(jìn)程間同步互斥中的應(yīng)用
1、互斥訪問(wèn)共享資源
在進(jìn)程間共享同一資源時(shí),要保證該資源不會(huì)被多個(gè)進(jìn)程同時(shí)訪問(wèn),可以通過(guò)P(sv)和V(sv)操作來(lái)實(shí)現(xiàn)。
while(1){
P(sem_id);
if(共享資源_空閑){
訪問(wèn)共享資源;
V(sem_id);
break;
}
V(sem_id);
}
2、進(jìn)程間并發(fā)控制
進(jìn)程間并發(fā)控制是指多個(gè)進(jìn)程都對(duì)同一資源進(jìn)行處理時(shí),它們相互合作、競(jìng)爭(zhēng),互相影響。通過(guò)設(shè)置信號(hào)量,可實(shí)現(xiàn)對(duì)進(jìn)程間的并發(fā)進(jìn)行控制。
3、防止死鎖
死鎖是指兩個(gè)或多個(gè)進(jìn)程在執(zhí)行過(guò)程中,因爭(zhēng)奪資源而造成一種互相等待的現(xiàn)象,若無(wú)外力作用,將無(wú)法繼續(xù)執(zhí)行下去。當(dāng)進(jìn)程需要訪問(wèn)多個(gè)資源時(shí),通過(guò)設(shè)置信號(hào)量,就可以在訪問(wèn)一個(gè)資源后,才能通過(guò)P(sv)訪問(wèn)下一個(gè)資源,防止死鎖的發(fā)生。
成都網(wǎng)站建設(shè)公司-創(chuàng)新互聯(lián),建站經(jīng)驗(yàn)豐富以策略為先導(dǎo)10多年以來(lái)專注數(shù)字化網(wǎng)站建設(shè),提供企業(yè)網(wǎng)站建設(shè),高端網(wǎng)站設(shè)計(jì),響應(yīng)式網(wǎng)站制作,設(shè)計(jì)師量身打造品牌風(fēng)格,熱線:028-86922220進(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è)問(wèn)題 —— 如何讓進(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è)重要的問(wèn)題就是如何避免競(jìng)爭(zhēng),即避免多個(gè)進(jìn)程同時(shí)訪問(wèn)臨界區(qū)的資源。
共享內(nèi)存是進(jìn)程間通信中最簡(jiǎn)單的方式之一。共享內(nèi)存允許兩個(gè)或更多進(jìn)程訪問(wèn)同一塊內(nèi)存。當(dāng)一個(gè)進(jìn)程改變了這塊地址中的內(nèi)容的時(shí)候,其它進(jìn)程都會(huì)察覺到這個(gè)更改。
你可能會(huì)想到,我直接創(chuàng)建一個(gè)文件,然后進(jìn)程不就都可以訪問(wèn)了?
是的,但這個(gè)方法有幾個(gè)缺陷:
Linux下采用共享內(nèi)存的方式來(lái)使進(jìn)程完成對(duì)共享資源的訪問(wèn),它將磁盤文件復(fù)制到內(nèi)存,并創(chuàng)建虛擬地址到該內(nèi)存的映射,就好像該資源本來(lái)就在進(jìn)程空間之中,此后我們就可以像操作本地變量一樣去操作它們了,實(shí)際的寫入磁盤將由系統(tǒng)選擇更佳方式完成,例如操作系統(tǒng)可能會(huì)批量處理加排序,從而液帆大大提高IO速度。
如同上圖一樣,進(jìn)程將共享內(nèi)存映射到自己的虛擬地址空間中,進(jìn)程訪問(wèn)共享進(jìn)程就好像在訪問(wèn)自己的虛擬內(nèi)存一樣,速度是非??斓?。
共享內(nèi)存的模型應(yīng)該是比較好理解的:在物理內(nèi)存中創(chuàng)建一個(gè)共享資源文件,進(jìn)程將該共享內(nèi)存綁定到自己的虛擬內(nèi)存之中。
這里要解決的一個(gè)問(wèn)題是如何將同一塊共享內(nèi)存綁定到自己的虛擬內(nèi)存中,要知道在不同進(jìn)程中使用 malloc 函數(shù)是會(huì)順序分配空閑內(nèi)存,而不會(huì)分配同一塊內(nèi)存,那么要如何去解決這個(gè)問(wèn)題呢?
Linux操作系統(tǒng)已經(jīng)想辦法幫我們解決了這個(gè)問(wèn)題,在 #include 和 #include 頭文件下,有如下幾個(gè)shm系列函數(shù):
通過(guò)上述幾個(gè)函數(shù),每個(gè)獨(dú)立的進(jìn)程只要有統(tǒng)一的共享內(nèi)存標(biāo)識(shí)符便可以建立起虛擬地址到物理地址的映射,每個(gè)虛擬地址將被翻譯成指向共享區(qū)域的物理地址,這樣就實(shí)現(xiàn)了對(duì)共享內(nèi)存的訪問(wèn)。
還有一種相像的實(shí)現(xiàn)是采用mmap函數(shù),mmap通常是直接對(duì)磁盤的映射——因此不算是共享內(nèi)存,存儲(chǔ)量非常大,但訪問(wèn)慢;
shmat與此相反,通常將資源保存在內(nèi)存中創(chuàng)建映射,訪問(wèn)快,但存儲(chǔ)量較小。
不過(guò)要注意一點(diǎn),操作系統(tǒng)并不保證任何并發(fā)問(wèn)題,例如兩個(gè)進(jìn)程同時(shí)更改同一塊內(nèi)存區(qū)域,正如你和你的朋友在線編輯同一個(gè)文檔中的同一個(gè)標(biāo)題,這會(huì)導(dǎo)致一些不好的結(jié)果,所以我們需要借助信號(hào)量或其他方式來(lái)完成同步。
信號(hào)量是迪杰斯特拉更先提出的一種為解決 同步不同執(zhí)行線程問(wèn)題 的一種方法,進(jìn)程與線程抽象來(lái)看大同小異,所以
信號(hào)量同樣可以用于同步進(jìn)程間通信
。
信號(hào)量 s 是具有非負(fù)整數(shù)值的全局變量,由兩種特殊的
原子操作
來(lái)實(shí)現(xiàn),這兩種原子操作稱為 P 和 V :
信號(hào)量并不用來(lái)傳送資源,而是用來(lái)保護(hù)共享資源,理解這一點(diǎn)是很重要的,信號(hào)量 s 的表示的含義為
同時(shí)允許更大訪問(wèn)資源的進(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)程能夠訪問(wè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)行封裝:
正如其名,管道就如同生活中的一根管道,一端輸送,而另一端接收,雙方不需要知道對(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表示成功或者失?。?/p>
int pipe(int fd)
這個(gè)函數(shù)打開兩個(gè)文件描述符,一個(gè)讀端文件,一個(gè)寫端,分別存入fd和fd中,然后可以作為參數(shù)調(diào)用 write 和 read 函數(shù)進(jìn)行寫入或讀取,注意fd只能讀取文件,而fd只能用于寫入文件。
你可能有個(gè)疑問(wèn),這要怎么實(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ù)問(wèn)題,管道被設(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ā)問(wèn)題。
了解了匿名管道之后,有名管道便很好理解了。在匿名管道的介紹中,我們說(shuō)其他進(jìn)程不知道管道和文件描述符的存在,所以匿名管道只適用于具有親緣關(guān)系的進(jìn)程,而命名管道則很好的解決了這個(gè)問(wèn)題 —— 現(xiàn)在管道有一個(gè)唯一的名稱了,任何進(jìn)程都可以訪問(wèn)這個(gè)管道。
注意,操作系統(tǒng)將管道看作一個(gè)抽象的文件,但管道并不是普通的文件,管道存在于內(nèi)核空間中而不放置在磁盤(有名管道文件系統(tǒng)上有一個(gè)標(biāo)識(shí)符,沒有數(shù)據(jù)塊),訪問(wèn)速度更快,但存儲(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ì)列亦稱報(bào)文隊(duì)列,也叫做信箱,是Linux的一種通信機(jī)制,這種通信機(jī)制傳遞的數(shù)據(jù)會(huì)被拆分為一個(gè)一個(gè)獨(dú)立的數(shù)據(jù)塊,也叫做消息體,消息體中可以定義類型與數(shù)據(jù),克服了無(wú)格式承載字節(jié)流的缺陷(現(xiàn)在收到void*后可以知道其原本的格式惹):
同管道類似,它有一個(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ù)雜度。
一個(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ī)制。
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)行剖析。
對(duì)于工作而言,我們可能一輩子都用不上這些操作,但作為對(duì)于操作系統(tǒng)的學(xué)習(xí),認(rèn)識(shí)到進(jìn)程間是如何通信還是很有必要的。
關(guān)于linux 多進(jìn)程間sem的介紹到此就結(jié)束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關(guān)注本站。
成都創(chuàng)新互聯(lián)科技公司主營(yíng):網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)、小程序制作、成都軟件開發(fā)、網(wǎng)頁(yè)設(shè)計(jì)、微信開發(fā)、成都小程序開發(fā)、網(wǎng)站制作、網(wǎng)站開發(fā)等業(yè)務(wù),是專業(yè)的成都做小程序公司、成都網(wǎng)站建設(shè)公司、成都做網(wǎng)站的公司。創(chuàng)新互聯(lián)公司集小程序制作創(chuàng)意,網(wǎng)站制作策劃,畫冊(cè)、網(wǎng)頁(yè)、VI設(shè)計(jì),網(wǎng)站、軟件、微信、小程序開發(fā)于一體。
標(biāo)題名稱:Linux下多進(jìn)程間sem的原理和應(yīng)用(linux多進(jìn)程間sem)
文章地址:http://www.dlmjj.cn/article/cddoeec.html


咨詢
建站咨詢
