摘要:
進程的用戶空間是互相獨立的,一般而言是不能互相訪問的,唯一的例外是共享內存區。另外,系統空間是“公共場所”,各進程均可以訪問,所以內核也可以提供這樣的條件。此外,還有雙方都可以訪問的外設。在這個意義上,兩個進程當然也可以通過磁盤上的普通文件交換信息,或者通過“註冊表”或其它數據庫中的某些表項和記錄交換信息。廣義上這也是進程間通信的手段,但是一般都不把這算作“進程間通信”。
簡介:
進程間通信(IPC,Interprocess communication)是一組編程接口,讓程序員能夠協調不同的進程,使之能在一個操作系統裏同時運行,並相互傳遞、交換信息。
進程間通信主要包括管道, 系統IPC(包括消息隊列,信號,共享存儲), 套接字(SOCKET)。系統IPC的三種方式類同,都是使用了內核裏的標識符來識別.
進程間通信的目的:
1)數據傳輸:一個進程需要將它的數據發送給另一個進程,發送的數據量在一個字節到幾兆字節之間。
2)共享數據:多個進程想要操作共享數據,一個進程對共享數據的修改,別的進程應該立刻看到。
3)通知事件:一個進程需要向另一個或一組進程發送消息,通知它(它們)發生了某種事件(如進程終止時要通知父進程)。
4)資源共享:多個進程之間共享同樣的資源。爲了作到這一點,需要內核提供鎖和同步機制。
5)進程控制:有些進程希望完全控制另一個進程的執行(如Debug進程),此時控制進程希望能夠攔截另一個進程的所有陷入和異常,並能夠及時知道它的狀態改變。
進程通過與內核及其它進程之間的互相通信來協調它們的行爲。Linux支持多種進程間通信(IPC)機制,信號和管道是其中的兩種。除此之外,Linux還支持System V 的IPC機制(用首次出現的Unix版本命名)
信號:
在一個信號的生命週期中有兩個階段:生成和傳送。當一個事件發生時,需要通知一個進程,這時生成一個信號。當進程識別出信號的到來,就採取適當的動作來傳送或處理信號。在信號到來和進程對信號進行處理之間,信號在進程上掛起
幾種常見的信號:
SIGHUP: 從終端上發出的結束信號;
SIGINT: 來自鍵盤的中斷信號(Ctrl-C);
SIGQUIT:來自鍵盤的退出信號(Ctrl-\);
SIGFPE: 浮點異常信號(例如浮點運算溢出);
SIGKILL:該信號結束接收信號的進程;
SIGALRM:進程的定時器到期時,發送該信號;
SIGTERM:kill 命令發出的信號;
SIGCHLD:標識子進程停止或結束的信號;
SIGSTOP:來自鍵盤(Ctrl-Z)或調試程序的停止執行信號;
管道:
管道是單向的、先進先出的、無結構的、固定大小的字節流,它把一個進程的標準輸出和另一個進程的標準輸入連接在一起。寫進程在管道的尾端寫入數據,讀進程在管道的首端讀出數據。數據讀出後將從管道中移走,其它讀進程都不能再讀到這些數據。
管道提供了簡單的流控制機制。進程試圖讀空管道時,在有數據寫入管道前,進程將一直阻塞。同樣,管道已經滿時,進程再試圖寫管道,在其它進程從管道中移走數據之前,寫進程將一直阻塞。
系統V IPC機制:
常用的三種進程間通信機制(IPC)機制:消息隊列、信號燈和共享內存(message queues,semaphores and shared memory
Message Queues(消息隊列)
消息隊列就是消息的一個鏈表,它允許一個或多個進程向它寫消息,一個或多個進程從中讀消息。Linux維護了一個消息隊列向量表:msgque,來表示系統中所有的消息隊列。
從隊列中讀消息與向隊列中寫消息是一個相似的過程。進程對消息隊列的訪問權限一樣要被檢查。讀進程可以選擇從隊列中讀取第一條消息而不管消息的類型,也可以選擇從隊列中讀取特殊類型的消息。如果沒有符合條件的消息,讀進程會被加到消息隊列的讀等待隊列,然後運行調度程序。當一個新的消息寫到消息隊列時,這個進程會被喚醒,繼續它的運行。
Linux提供了四個消息隊列操作:
1、創建或獲得消息隊列(MSGGET):int sys_msgget (key_t key, int msgflg)
2、發送消息:int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
3、接收消息:int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz,
4、消息控制:int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
消息隊列和管道提供相似的服務,但消息隊列要更加強大並解決了管道中所存在的一些問題。消息隊列傳遞的消息是不連續的、有格式的信息,給對它們的處理帶來了很大的靈活性。可以用不同的方式解釋消息的類型域,如可以將消息的類型同消息的優先級聯繫起來,類型域也可以用來指定接收者。
小消息的傳送效率很高,但大消息的傳送性能則較差。因爲消息傳送的過程中要經過從用戶空間到內核空間,再從內核空間到用戶空間的拷貝,所以,大消息的傳送其性能較差。另外,消息隊列不支持廣播,而且內核不知道消息的接收者
共享內存:
在進行間同步的方式彙總,共享內存速度最快。常見的操作:
1、int shmget(key_t key, int size, int flag); /* 獲得一個共享存儲標識符*/
2、void *shmat(int shmid, void *addr, int flag); /* 將共享內存連接到自身地址空間中*/
如果一個進程通過fork創建了子進程,則子進程繼承父進程的共享內存,既而可以直接對共享內存使用,不過子進程可以自身脫離共享內存。
進程間通信各種方式效率比較:
類型 |
無連接 |
可靠 |
流控制 |
消息類型優先級 |
普通PIPE |
N |
Y |
Y |
N |
流PIPE |
N |
Y |
Y |
N |
命名PIPE(FIFO) |
N |
Y |
Y |
N |
消息隊列 |
N |
Y |
Y |
Y |
信號量 |
N |
Y |
Y |
Y |
共享存儲 |
N |
Y |
Y |
Y |
UNIX流SOCKET |
N |
Y |
Y |
N |
UNIX數據包SOCKET |
Y |
Y |
N |
N |
後附共享內存實現進程間通信的源碼:
連接待續。。。。。。。