本篇文章給大家?guī)砹岁P(guān)于linux進(jìn)程間通信的相關(guān)知識,其中包括管道、匿名管道、共享內(nèi)存等相關(guān)問題,希望對大家有幫助。
·進(jìn)程間通信:操作系統(tǒng)為系統(tǒng)提供的用于實(shí)現(xiàn)進(jìn)程間通信的方式
進(jìn)程之間是無法直接通信的,因?yàn)槊總€(gè)進(jìn)程都有獨(dú)立的虛擬地址空間,訪問的都是自己的虛擬地址,因此進(jìn)程具有獨(dú)立性,無法直接通信
根據(jù)通信場景的不同,因此提供了多種不同的通信方式
進(jìn)程間通信方式種類:管道、共享內(nèi)存、消息隊(duì)列、信號量
·管道
特性:半雙工通信–可以選擇方向的單向通信
本質(zhì):在內(nèi)核中開辟一塊緩沖區(qū)(內(nèi)核空間中的一塊內(nèi)存)
原理:多個(gè)進(jìn)程通過訪問同一塊內(nèi)核中的緩沖區(qū)實(shí)現(xiàn)通信(復(fù)制緩沖區(qū)的操作句柄)
分類:匿名管道:緩沖區(qū)沒有標(biāo)識符,只能用于具有親緣關(guān)系的進(jìn)程間通信
命名管道:緩沖區(qū)具有標(biāo)識符,可用于同一主機(jī)上任意的進(jìn)程間通信
linux下一切皆文件–所有東西都是當(dāng)做文件一樣進(jìn)行操作(包括管道),通過IO操作完成對管道的訪問
·匿名管道
返回值:成功返回0;失敗返回-1
特性:只能用于具有親緣關(guān)系的進(jìn)程間通信
匿名管道沒有標(biāo)識符,無法被其他進(jìn)程找到,只能通過子進(jìn)程復(fù)制父進(jìn)程的方式獲取到操作句柄實(shí)現(xiàn)通信
讀寫特性:若管道中沒有數(shù)據(jù),則read會阻塞
若管道中數(shù)據(jù)滿了,則write會阻塞
所有的管道的讀端被關(guān)閉,則繼續(xù)write則會觸發(fā)異常,導(dǎo)致進(jìn)程崩潰退出
所有的管道的寫端被關(guān)閉,則繼續(xù)read則會讀完數(shù)據(jù)后返回0,不再阻塞
注:管道是半雙工通信,在通信時(shí),一旦選定了 方向,應(yīng)將不使用的那一端關(guān)閉。
· 命名管道:本質(zhì)是 內(nèi)核中的一塊緩沖區(qū),具有標(biāo)識符,可以被其他進(jìn)程找到,因此可用于同一主機(jī)上的任意進(jìn)程間通信
命名管道的標(biāo)識符就是一個(gè)可見于文件系統(tǒng)的管道類型文件
多個(gè)進(jìn)程通過打開同一個(gè)管道文件,訪問同一塊內(nèi)核中的緩沖區(qū)實(shí)現(xiàn)通信
命令操作:mkfifo filename 創(chuàng)建一個(gè)命名管道文件
函數(shù)操作:int mkfifo(const char *pathname, mode_t mode);
pathname:文件名稱;mode:創(chuàng)建權(quán)限
返回值:成功返回0;失敗返回-1
·總結(jié):管道的本質(zhì):內(nèi)核空間中的一塊緩沖區(qū)
原理:多個(gè)進(jìn)程通過訪問同一塊緩沖區(qū)實(shí)現(xiàn)數(shù)據(jù)傳輸
分類:匿名管道、命名管道
匿名管道:只能用于具有親緣關(guān)系的進(jìn)程間通信
命名管道:可以用于同一主機(jī)上任意進(jìn)程間通信
特性:①半雙工通信–可以選擇方向的單向通信
提供字節(jié)流傳輸服務(wù):有序的、可靠的、基于連接的一種流式傳輸
基于連接:所有讀端關(guān)閉則write異常;所有寫端關(guān)閉則read返回0
②自帶同步與互斥:
同步:通過同一時(shí)間進(jìn)程對臨界資源的唯一訪問實(shí)現(xiàn)訪問操作安全
互斥:通過一些條件判斷讓進(jìn)程對臨界資源的訪問更加合理有序
互斥的體現(xiàn):對管道進(jìn)行寫入操作的大小不超過PIPE_BUF-4096大小,則保證操作的原子性
同步的體現(xiàn):管道沒有數(shù)據(jù)則read阻塞,管道數(shù)據(jù)寫滿則write阻塞
③生命周期隨進(jìn)程:不人為干預(yù)情況下,所有打開管道的進(jìn)程退出后,管道緩沖區(qū)被釋放
·共享內(nèi)存:用于實(shí)現(xiàn)進(jìn)程間的數(shù)據(jù)共享
本質(zhì):一塊物理內(nèi)存
原理:開辟一塊物理內(nèi)存空間,多個(gè)進(jìn)程將同一塊映射到自己的虛擬地址空間,通過虛擬地址直接進(jìn)行訪問,進(jìn)而實(shí)現(xiàn)數(shù)據(jù)共享
特性:最快的進(jìn)程間通信方式,生命周期隨內(nèi)核
共享內(nèi)存通過虛擬地址直接訪問物理內(nèi)存,實(shí)現(xiàn)數(shù)據(jù)共享,相對于其他方式需要將數(shù)據(jù)拷貝到內(nèi)核,使用時(shí)拷貝到用戶態(tài),少了兩次數(shù)據(jù)拷貝操作
注意事項(xiàng):對共享內(nèi)存的操作需要注意安全問題
操作流程:
①創(chuàng)建或打開共享內(nèi)存
②將共享內(nèi)存映射到進(jìn)程的虛擬地址空間
③通過映射的虛擬地址進(jìn)行各種內(nèi)存操作
④解除映射關(guān)系
⑤刪除共享內(nèi)存
int shmget(key_t key, size_t size, int shmflg);
key:標(biāo)識符(多個(gè)進(jìn)程通過相同的標(biāo)識符打開同一塊共享內(nèi)存)
size:創(chuàng)建時(shí)所開辟的空間大小(以內(nèi)存頁為單位)
shmflg:打開方式 + 創(chuàng)建權(quán)限–IPC_CREAT|IPC_EXCL|0664
返回值: 成功返回一個(gè)非負(fù)整數(shù)–操作句柄;失敗返回-1
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmid:shmget返回的操作句柄
shmaddr:映射地址,通常設(shè)置為NULL
shmflg:映射成功后的訪問方式;SHM_RDONLY-只讀;0-讀寫
返回值:成功則返回映射后的首地址;失敗返回(void *)-1
int shmdt(const void *shmaddr);
shmaddr:映射后的首地址
返回值:成功返回0;失敗返回-1
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmid:shmget返回的操作句柄
cmd:操作類型–IPC_RMID 標(biāo)記共享內(nèi)存為被銷毀
buf:對于IPC_RMID,成功返回0,失敗發(fā)返回-1
·消息隊(duì)列
本質(zhì):內(nèi)核中的一個(gè)優(yōu)先級隊(duì)列,多個(gè)進(jìn)程通過訪問同一個(gè)隊(duì)列,向隊(duì)列中添加或者獲取節(jié)點(diǎn)而實(shí)現(xiàn)進(jìn)程間的數(shù)據(jù)塊傳輸
特性:自帶同步與互斥,生命周期隨內(nèi)核
·信號量
本質(zhì):內(nèi)核中的一個(gè)計(jì)數(shù)器 + pcb等待隊(duì)列
作用:用于實(shí)現(xiàn)進(jìn)程間的同步與互斥,協(xié)調(diào)進(jìn)程對臨界資源的訪問
P操作:計(jì)數(shù)器-1,判斷若計(jì)數(shù)小于0則阻塞進(jìn)程
V操作:計(jì)數(shù)器+1,喚醒一個(gè)阻塞的進(jìn)程
通過自身的計(jì)數(shù)器對資源進(jìn)行計(jì)數(shù),通過計(jì)數(shù)判斷進(jìn)程對資源的獲取是否合理,不合理則阻塞。等待產(chǎn)生一個(gè)資源之后,喚醒阻塞的進(jìn)程
同步的實(shí)現(xiàn):通過計(jì)數(shù)器對資源進(jìn)行計(jì)數(shù),在獲取資源之前進(jìn)行P操作
互斥的實(shí)現(xiàn):計(jì)數(shù)器為1,表示資源只有一個(gè),進(jìn)程訪問資源之前進(jìn)行P操作,訪問完畢后進(jìn)行V操作