生活随笔
收集整理的這篇文章主要介紹了
Linux系统编程---4(进程间通信IPC,管道)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
進程間通信目的
數據傳輸:一個進程需要將它的數據發送給另一個進程 資源共享:多個進程之間共享同樣的資源。 通知事件:一個進程需要向另一個或一組進程發送消息,通知它(它們)發生了某種事件(如進程終止 時要通知父進程)。 進程控制:有些進程希望完全控制另一個進程的執行(如Debug進程),此時控制進程希望能夠攔截另 一個進程的所有陷入和異常,并能夠及時知道它的狀態改變
IPC
linux系統下7中文件類型
-- 文件 d 目錄 l 符號鏈接 偽文件:(不占用內存) s 套接字 b 塊設備 c 字符設備 p 管道 Linux 環境下,進程地址空間相互獨立,每個進程各自有不同的用戶地址空間。任何一個進程的全局變量在另 一個進程中都看不到,所以進程和進程之間不能相互訪問,要交換數據必須通過內核,在內核中開辟一塊緩沖區, 進程 1 把數據從用戶空間拷到內核緩沖區,進程2 再從內核緩沖區把數據讀走,內核提供的這種機制稱為進程間通 信(IPC,InterProcessCommunication)。 在進程間完成數據傳遞需要借助操作系統提供特殊的方法,如:文件、管道、信號、共享內存、消息隊列、套 接字、命名管道等。隨著計算機的蓬勃發展,一些方法由于自身設計缺陷被淘汰或者棄用。現今常用的進程間通信 方式 有: 管道 (使用最簡單) pipe(管道一般讀寫行為) fifo(有名管道,用于非血緣關系) 信號 (開銷最小) 共享映射區 (無血緣關系) 本地套接字 (最穩定)
管道
管道的概念:
管道是一種最基本的 IPC 機制,作用于有血緣關系的進程之間,完成數據傳遞。調用 pipe 系統函數即可創建一 個管道。
管道特質:
其本質是一個偽文件(實為內核緩沖區) 由兩個文件描述符引用,一個表示讀端,一個表示寫端。 規定數據從管道的寫端流入管道,從讀端流出。
管道的原理:
管道實為內核使用環形隊列機制 ,借助內核緩沖區(4k)實現。
管道的局限性:
數據自己讀不能自己寫。 數據一旦被讀走,便不在管道中存在,不可反復讀取。 由于管道采用半雙工通信方式。因此,數據只能在一個方向上流動 只能在有公共祖先的進程間使用管道
常見的通信方式
單工通信,只能收不能發 半雙工通信,數據只能在一個方向上流動 全雙工通信。
管道的特點
只能用于具有共同祖先的進程(具有親緣關系的進程)之間進行通信;通常,一個管道由一個進程創 建,然后該進程調用fork,此后父、子進程之間就可應用該管道。 管道提供流式服務 一般而言,進程退出,管道釋放,所以管道的生命周期隨進程 一般而言,內核會對管道操作進行同步與互斥 管道是半雙工的,數據只能向一個方向流動;需要雙方通信時,需要建立起兩個管道
pipe 函數
int pipe (int pipefd[2] ); 成功:0;失敗:-1,設置 errno
函數調用成功返回 r/w 兩個文件描述符。無需 open,但需手動 close。規定:fd[0] → r; fd[1] → w,就像 0 對應標準輸入,1 對應標準輸出一樣。向管道文件讀寫數據其實是在讀寫內核緩沖區。 管道創建成功以后,創建該管道的進程(父進程)同時掌握著管道的讀端和寫端。如何實現父子進程間通信呢? 通常可以采用如下步驟:
父進程調用 pipe 函數創建管道,得到兩個文件描述符 fd[0]、fd[1]指向管道的讀端和寫端。
父進程調用 fork 創建子進程,那么子進程也有兩個文件描述符指向同一管道。
父進程關閉管道讀端,子進程關閉管道寫端。父進程可以向管道中寫入數據,子進程將管道中的數據讀出。 由于管道是利用環形隊列實現的,數據從寫端流入管道,從讀端流出,這樣就實現了進程間通信。
#include<stdio.h>#include<unistd.h>#include<stdlib.h>#include<string.h>int main(void){int fd[2];pid_t pid;int ret=pipe(fd);if(ret==-1){ perror("pipe error:");exit(1);} pid = fork();if(pid==-1){perror("perror error:");exit(1);}else if(pid==0){ //子進程 讀數據 close(fd[1]);//關閉管道的寫端char buf[1024];ret=read(fd[0],buf,sizeof(buf));if(ret == 0){ printf("----\n");} write(STDOUT_FILENO,buf,ret);}else{ //父進程寫數據sleep(1); close(fd[0]);//關掉管道的讀端write(fd[1],"hello pipe\n",strlen("hello pipe\n"));} }
管道的讀寫行為
使用管道需要注意以下 4 種特殊情況(假設都是阻塞 I/O 操作,沒有設置 O_NONBLOCK 標志) :
如果所有指向管道寫端的文件描述符都關閉了(管道寫端引用計數為 0),而仍然有進程從管道的讀端讀數 據,那么管道中剩余的數據都被讀取后,再次 read 會返回 0,就像讀到文件末尾一樣。 如果有指向管道寫端的文件描述符沒關閉(管道寫端引用計數大于 0),而持有管道寫端的進程也沒有向管 道中寫數據,這時有進程從管道讀端讀數據,那么管道中剩余的數據都被讀取后,再次 read 會阻塞,直到管道中有 數據可讀了才讀取數據并返回。 如果所有指向管道讀端的文件描述符都關閉了(管道讀端引用計數為 0),這時有進程向管道的寫端 write, 那么該進程會收到信號 SIGPIPE,通常會導致進程異常終止。當然也可以對 SIGPIPE 信號實施捕捉,不終止進程。具 體方法信號章節詳細介紹。 如果有指向管道讀端的文件描述符沒關閉(管道讀端引用計數大于 0),而持有管道讀端的進程也沒有從管 道中讀數據,這時有進程向管道寫端寫數據,那么在管道被寫滿時再次 write 會阻塞,直到管道中有空位置了才寫 入數據并返回。
總結
讀管道
管道中有數據,read 返回實際讀到的字節數 管道中無數據: (1) 管道寫端被全部關閉,read 返回 0(好像讀到文件結尾) (2) 寫端沒有全部被關閉,read 阻塞等待(不久的將來可能有數據遞達,此時會讓出 cpu)
寫管道
管道讀端全部被關閉, 進程異常終止(也可使用捕捉 SIGPIPE 信號,使進程不終止) 管道讀端沒有全部關閉: (1) 管道已滿,write 阻塞。 (2) 管道未滿,write 將數據寫入,并返回實際寫入的字節數。
管道緩沖區大小
可以使用 ulimit–a 命令來查看當前系統中創建管道文件所對應的內核緩沖區大小。通常為:
pipe size (512bytes,-p)8
也可以使用 fpathconf 函數,借助參數 選項來查看。使用該宏應引入頭文件<unistd.h>
long fpathconf(int fd,int name); 成功:返回管道的大小 失敗:-1,設置 errno
管道的優劣
優點:簡單,相比信號,套接字實現進程間通信,簡單很多。 缺點:
只能單向通信,雙向通信需建立兩個管道。 只能用于父子、兄弟進程(有共同祖先)間通信。該問題后來使用 fifo 有名管道解決。
FIFO
FIFO 常被稱為命名管道,以區分管道(pipe)。管道(pipe)只能用于“有血緣關系”的進程間。但通過 FIFO,不相 關的進程也能交換數據。 FIFO 是 Linux 基礎文件類型中的一種。但,FIFO 文件在磁盤上沒有數據塊,僅僅用來標識內核中一條通道。各 進程可以打開這個文件進行 read/write,實際上是在讀寫內核通道,這樣就實現了進程間通信。 創建方式:
命令:mkfifo 管道名 庫函數:int mkfifo(const char*pathname, mode_t mode); 成功:0; 失敗:-1 一旦使用 mkfifo 創建了一個 FIFO,就可以使用 open 打開它,常見的文件 I/O 函數都可用于 fifo。如: close、 read、 write、unlink 等。
總結
以上是生活随笔 為你收集整理的Linux系统编程---4(进程间通信IPC,管道) 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。