关于进程间通信的学习心得
進(jìn)程:進(jìn)程是指獨立地址空間的指令序列
進(jìn)程的五種狀態(tài):新建,就緒,運行,睡眠,僵死
進(jìn)程間通信:是不同進(jìn)程之間進(jìn)行一些"接觸",這種接觸有簡單,有復(fù)雜。機(jī)制不同,復(fù)雜度也不同。通信是一個廣義上的意義,不僅指大批量數(shù)據(jù)傳送,還包括控制信息的傳送,但使用方法是基本相同的。
基本的進(jìn)程通信機(jī)制
1.傳統(tǒng)UNIX-IPC機(jī)制:信號和管道
2.SystemV的IPC機(jī)制:共享內(nèi)存、信號量和消息隊列
3.起源于Unix BSD版本的套結(jié)字(Socket)
4.遠(yuǎn)程過程調(diào)用(RPC)
信號:Unix系統(tǒng)中使用的最古老的進(jìn)程間通訊的方法之一,用于向一個或多個進(jìn)程發(fā)送異步事件的信號。信號可以類比于DOS下的INT或者是Windows下的事件。在有一個信號發(fā)生的時候,相應(yīng)的信號就會發(fā)送給相應(yīng)的進(jìn)程。
信號機(jī)制的實現(xiàn)
1.信號包括待處理信號和被阻塞信號
2.如果產(chǎn)生了一個被阻塞的信號,它一直保留待處理,直到被解除阻塞。
3.系統(tǒng)保存每一個進(jìn)程如何處理每一種可能的信號的信息。
4.系統(tǒng)判斷進(jìn)程是希望忽略這個信號還是讓內(nèi)核處理。進(jìn)程通過執(zhí)行系統(tǒng)調(diào)用改變?nèi)笔〉男盘柼幚怼?/span>
對信號的處理
1.初始化信號集,只有在信號集里面的信號才會被考慮
2.安裝信號處理器。所謂信號處理器,就是指定了一些對信號的處理方法。在安裝的時候,一定要對特定的信號賦予正確的信號處理函數(shù)。
信號相關(guān)函數(shù)
int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);為進(jìn)程安裝信號處理器,struct sigaction數(shù)據(jù)結(jié)構(gòu)是用來保存信號處理器的相關(guān)信息。
int sigemptyset(sigset_t *set);將信號集合清空。
int sigfillset(sigset_t *set);將信號集合設(shè)置成包含所有的信號,在對信號進(jìn)行操作以前一定要對信號集進(jìn)行初始化。
int sigaddset(sigset_t *set, int signo);向信號集中加入signo對應(yīng)的新信號。
int sigdelset(sigset_t *set, int signo);從信號集中刪除signo對應(yīng)的一個信號。
int sigismember(const sigset_t *set, int signo);判斷某個信號是否在信號集中。
int sigprocmask(int how,const sigset_t *set, sigset_t *oset);設(shè)置進(jìn)程的信號屏蔽碼。信號屏蔽碼可以用來在某段時間內(nèi)阻塞一些信號集中的信號。
管道通信:是最古老的Unix IPC工具,一個進(jìn)程從管道一頭寫數(shù)據(jù),另一個進(jìn)程從管道另一頭讀數(shù)據(jù),以實現(xiàn)它們之間通信的共享方式,又稱pipe文件。由于發(fā)送和接收都是利用管道進(jìn)行通信的,故稱為管道通信。通信方式是單向的。管道類型分為:無名管道、命名管道
管道通信的思想
1.發(fā)送進(jìn)程可以源源不斷的從pipe一端寫入數(shù)據(jù)流,在規(guī)定的pipe文件的最大長度(如4096字節(jié))范圍內(nèi),每次寫入的信息長度是可變的。
2.接收進(jìn)程在需要時可以從pipe的另一端讀出數(shù)據(jù),讀出單位長度也是可變的。
基本管道調(diào)用函數(shù)
int do_pipe(int *fd);創(chuàng)建管道
static int pipe_release(struct inode *inode, int decr, int decw);管道釋放
無名管道II
顯示了每一個file數(shù)據(jù)結(jié)構(gòu)包含了不同的文件操作例程的向量表的指針:一個用于寫,另一個從管道中讀。這掩蓋了和通用的讀寫普通文件的系統(tǒng)調(diào)用的不同。當(dāng)寫進(jìn)程向管道中寫的時候,字節(jié)拷貝到了共享的數(shù)據(jù)頁,當(dāng)從管道中讀的時候,字節(jié)從共享頁中拷貝出來。
命名管道:又名FIFO,它不是臨時的對象,而是文件系統(tǒng)中的實體,可以用mkfifo命令創(chuàng)建。系統(tǒng)必須處理在寫進(jìn)程打開FIFO之前打開FIFO讀的進(jìn)程,以及在寫進(jìn)程寫數(shù)據(jù)之前讀的進(jìn)程。它使用和無名管道一樣的數(shù)據(jù)結(jié)構(gòu)和操作。
???????(寫入端)[Fd1]→pipe(fd)→[Fd0](讀出端)
信號量:信號量(Semaphore)和信號是不同的東西,信號是實現(xiàn)約定的固定的值,而信號量是一個變量記錄著某些特定信息,它的使用主要是用來保護(hù)共享資源,使得該資源在一個時刻只讓一個進(jìn)程擁有。
信號量的數(shù)據(jù)結(jié)構(gòu):使用semid_ds數(shù)據(jù)結(jié)構(gòu)表達(dá)信號量。系統(tǒng)中所有的semid_ds數(shù)據(jù)結(jié)構(gòu)都由semary指針向量表指向。每一個信號燈數(shù)組中都有sem_nsems,通過sem_base指向的一個sem數(shù)據(jù)結(jié)構(gòu)來描述
信號量機(jī)制的實現(xiàn)
1.對信號量的操作只有兩個:P、V。
2.為了在邏輯上便于組織信號量,信號量機(jī)制中有一個概念是信號量組。我們在一個信號量組中創(chuàng)建相關(guān)的信號量,這樣邏輯上清晰也便于管理。
3.在使用之前同樣需要對他們進(jìn)行初始化:生成或打開信號量組,向其中生成或刪除指定的信號量。
4.一個信號量必須屬于一個信號量組,否則不能被系統(tǒng)所使用。
5.信號量和信號量組是不會被系統(tǒng)所自動清理的,所以在進(jìn)程退出前,需要及時清理生成的那些信號量。
信號量的相關(guān)函數(shù)
int semget(key_t key, int nsems, int semflg);創(chuàng)建一個新的信號量組或獲取一個已經(jīng)存在的信號量組。
int semop(int semid, struct sembuf *sop, int nsops);一次對一個或多個信號量進(jìn)行操作,用于P、V操作。
Int semctl(int sem_id, int semnum, int cmd, union semun arg);用來獲取一些信號量的使用信息或者是來對信號量進(jìn)行控制。
共享內(nèi)存
????共享內(nèi)存是進(jìn)程通信的一個重要方法,為進(jìn)程提供了直接通信的手段。操作系統(tǒng)中一個或多個進(jìn)程通過同時出現(xiàn)在它們的虛擬地址空間的內(nèi)存通訊,該虛擬內(nèi)存被每個共享進(jìn)程的頁表所引用,它們的地址無需相同。進(jìn)程對共享內(nèi)存的訪問是受控的,信號量等機(jī)制實現(xiàn)了共享內(nèi)存訪問的同步
共享內(nèi)存的簡單原理
每一個新創(chuàng)建的內(nèi)存區(qū)域都用一個shmid_ds數(shù)據(jù)結(jié)構(gòu)來表達(dá)。這些數(shù)據(jù)結(jié)構(gòu)保存在shm_segs向量表中。Shmid_ds數(shù)據(jù)結(jié)構(gòu)描述了這個共享內(nèi)存取有多大、多少個進(jìn)程在使用它以及共享內(nèi)存如何映射到它們的地址空間。由共享內(nèi)存的創(chuàng)建者來控制對于這塊內(nèi)存的訪問權(quán)限和它的key是公開或私有。如果有足夠的權(quán)限它也可以把共享內(nèi)存鎖定在物理內(nèi)存中。每一個希望共享這塊內(nèi)存的進(jìn)程必須通過系統(tǒng)調(diào)用粘附(attach)到虛擬內(nèi)存。這為該進(jìn)程創(chuàng)建了一個新的描述這塊共享內(nèi)存的vm_area_struct數(shù)據(jù)結(jié)構(gòu)。進(jìn)程可以選擇共享內(nèi)存在它的虛擬地址空間的位置或者由Linux選擇一塊足夠的的空閑區(qū)域。這個新的vm_area_struct結(jié)構(gòu)放在由shmid_ds指向的vm_area_struct列表中。通過vm_next_shared和vm_prev_shared把它們連在一起。
共享內(nèi)存的基本函數(shù)
int shmget(key_t key,int size,int shmflg);建立新的共享內(nèi)存或一個已存在的共享內(nèi)存描述字
void *shmat(int shmid,const void *shmaddr,int shmflg);將物理共享內(nèi)存粘附到進(jìn)程虛擬地址空間
int shmdt(const void *shmaddr);進(jìn)程從其虛擬地址空間分離共享內(nèi)存
int shmctl(int shmid,int cmd,struct shmid_ds *buf);查詢及設(shè)置一個共享內(nèi)存
共享內(nèi)存機(jī)制的實現(xiàn)
在使用一個共享內(nèi)存之前我們調(diào)用shmat得到共享內(nèi)存的開始地址,使用結(jié)束以后我們使用
shmdt斷開這個內(nèi)存。
進(jìn)程通過系統(tǒng)調(diào)用粘附到虛擬內(nèi)存,即創(chuàng)建了一個新的描述這塊共享內(nèi)存的vm_area_struct數(shù)據(jù)結(jié)構(gòu),這個新的vm_area_struct結(jié)構(gòu)放在由shmid_ds指向的vm_area_struct列表中。通過vm_next_shared和vm_prev_shared把它們連在一起。
虛擬內(nèi)存在粘附的時候其實并沒有創(chuàng)建,而發(fā)生在第一個進(jìn)程試圖訪問它的時候。
第一個訪問共享內(nèi)存頁的進(jìn)程使得這一頁被創(chuàng)建,而隨后訪問的其他進(jìn)程使得此頁被加到它們的虛擬地址空間。
當(dāng)進(jìn)程不再需要共享虛擬內(nèi)存的時候,它們從中分離出來。只要仍舊有其他進(jìn)程在使用這塊內(nèi)存,這種分離只是影響當(dāng)前的進(jìn)程。
當(dāng)共享這塊內(nèi)存的最后一個進(jìn)程從中分離出的時候,共享內(nèi)存當(dāng)前在物理內(nèi)存中的頁被釋放
消息隊列:消息隊列是比較高級的一種進(jìn)程間通信方法,實現(xiàn)一個或多個進(jìn)程間message傳送,一個消息隊列可以被多個進(jìn)程所共享(IPC就是在這個基礎(chǔ)上進(jìn)行的);如果一個進(jìn)程的消息太多一個消息隊列放不下,也可以用多于一個的消息隊列(不過可能管理會比較復(fù)雜)。
消息隊列的基本函數(shù)
int msgget(key_t key, int msgflg);獲取一個存在的消息隊列的ID,或者是根據(jù)跟定的權(quán)限創(chuàng)建一個消息隊列。
int msgctl(int msqid, int cmd, struct msqid_ds *buf);用來從msqid_ds中獲取很多消息隊列本身的信息。
int msgsnd(int msqid, void *msgp, size_t msgsz, int msgflg);用于向隊列發(fā)送消息。
int msgrcv(int msqid, void *msgp, size_t msgsz, long int msgtyp, intmsgflg);從隊列中接收消息。
消息隊列的實現(xiàn)機(jī)制
消息隊列,是一個隊列的結(jié)構(gòu),隊列里面的內(nèi)容由用戶進(jìn)程自己定義。實際上,隊列里面記錄的是指向用戶自定義結(jié)構(gòu)的指針和結(jié)構(gòu)的大小。要使用message queue,首先要通過系統(tǒng)調(diào)用(msgget)產(chǎn)生一個隊列,然后,進(jìn)程可以用msgsnd發(fā)送消息到這個隊列,消息就是如上所說的結(jié)構(gòu)。別的進(jìn)程用msgrcv讀取。消息隊列一旦產(chǎn)生,除非明確的刪除(某個有權(quán)限的進(jìn)程或者用ipcrm命令)或者系統(tǒng)重啟。否則,產(chǎn)生的隊列會一直保留在系統(tǒng)中。而且,只要有權(quán)限,就可以對隊列進(jìn)行操作。消息隊列和管道很相似,實際上,管道就是用戶消息為1個字節(jié)的隊列。
消息隊列的寫進(jìn)程
每一次一個進(jìn)程試圖向?qū)戧犃袑懴?#xff0c;它的有效用戶和組的標(biāo)識符就要和隊列的ipc_perm數(shù)據(jù)結(jié)構(gòu)的模式比較。如果進(jìn)程可以想這個隊列寫,則消息會從進(jìn)程的地址空間寫到msg數(shù)據(jù)結(jié)構(gòu),放到消息隊列的最后。每一個消息都帶有進(jìn)程間約定的,應(yīng)用程序指定類型的標(biāo)記。
消息隊列的讀進(jìn)程
從隊列中讀是一個相似的過程。進(jìn)程的訪問權(quán)限一樣被檢查。一個讀進(jìn)程可以選擇是不管消息的類型從隊列中讀取第一條消息還是選擇特殊類型的消息。如果沒有符合條件的消息,讀進(jìn)程會被加到消息隊列的讀等待進(jìn)程,然后運行調(diào)度程序。當(dāng)一個新的消息寫到隊列的時候,這個進(jìn)程會被喚醒,繼續(xù)運行。
消息隊列的簡單流程
發(fā)送進(jìn)程?????????????????????????????接收流程
Send(m)??????????????????????????????Receive(m )
?? Begin?????????????????????????????????begin
???向系統(tǒng)申請一個消息緩沖區(qū)??????????????P(SM) 等待接的消息的個數(shù)
???P(mutex) 使用公用緩沖區(qū)???????????????P(mutex) 使用公用緩沖區(qū)
???將發(fā)送區(qū)消息m送入新申請的消息緩沖區(qū)??摘下消息隊列中的消息m
???把消息緩沖區(qū)掛入接收進(jìn)程的消息隊列?????將消息隊列m從緩沖區(qū)復(fù)制到接收區(qū)
???V(mutex)釋放緩沖區(qū)????????????????????釋放緩沖區(qū)
???V(SM)向接收進(jìn)程發(fā)送消息??????????????V(mutex) 釋放公用緩沖區(qū)
??End?????????????????????????????????????end
Socket
獨立于具體協(xié)議的網(wǎng)絡(luò)編程接口;
在ISO模型中,主要位于會話層和傳輸層。
網(wǎng)絡(luò)編程接口:UNIX BSD的套接字(socket)、UNIX System V的TLI
BSD Socket(伯克立套接字)是通過標(biāo)準(zhǔn)的UNIX文件描述符和其它程序通訊的一個方法,目前已經(jīng)被廣泛移植到各個平臺。
Socket的類型
流式套接字:提供了一個面向連接,可靠的數(shù)據(jù)傳輸服務(wù),數(shù)據(jù)無差錯,無重復(fù)地發(fā)送且按發(fā)送順序接收.內(nèi)設(shè)流量控制,避免數(shù)據(jù)流超限;數(shù)據(jù)被看作是字節(jié)流,無長度限制,FTP即用此
數(shù)據(jù)報套接字:提供了一個無連接服務(wù).數(shù)據(jù)包以獨立包形式被發(fā)送,不提供無差錯保證,數(shù)據(jù)可能丟失或重復(fù),并且接受順序無序,網(wǎng)絡(luò)文件系統(tǒng)NFS
原始套接字(SOCK_RAW):該接口允許對較低層次協(xié)議,如IP,ICMP直接訪問
基本套接字調(diào)用
創(chuàng)建套接字???????????????socket();
綁定本機(jī)端口???????????bind();
建立連接???????????????????connect();
接受連接???????????????????accept();
監(jiān)聽端口???????????????????listen();
數(shù)據(jù)傳輸???????????????????send(), recv()等
關(guān)閉套接字???????????????close();
Socket相關(guān)數(shù)據(jù)結(jié)構(gòu)
struct sockaddr_in
??????????{
??????????????????short int??? sin_family;????/*通信類型*/
??????????????????unsigned short int sin_port;???????/*端口號,網(wǎng)絡(luò)直接順序*/
??????????????????struct in_addr??
???????? }
總結(jié)
以上是生活随笔為你收集整理的关于进程间通信的学习心得的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《感兴二首》是哪个时期的作品?
- 下一篇: 等离子原理?