寫給大忙人讀的進程間通信(附進程同步源碼)

摘要:


        進程的用戶空間是互相獨立的,一般而言是不能互相訪問的,唯一的例外是共享內存區。另外,系統空間是“公共場所”,各進程均可以訪問,所以內核也可以提供這樣的條件。此外,還有雙方都可以訪問的外設。在這個意義上,兩個進程當然也可以通過磁盤上的普通文件交換信息,或者通過“註冊表”或其它數據庫中的某些表項和記錄交換信息。廣義上這也是進程間通信的手段,但是一般都不把這算作“進程間通信”。

 

簡介:


       進程間通信(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

 

後附共享內存實現進程間通信的源碼:

連接待續。。。。。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章