進程間通信又稱IPC(Inter Process Communication),它可以通過文件 管道 有名管道 共享內存 消息隊列 信號量 套接字這幾個方式進行通信,但是文件這種以及消息隊列基本已被淘汰。
所以常用的通信方式有:
1.管道
2.信號
3.共享映射區
4.本地套接字
而其中的管道機制,是屬於最簡單的一種通信方式。它適用於有血緣關系的進程之間的單向通信。它的本質是偽文件,是一段內核緩沖區。實現原理是內核使用環形隊列,借助內核緩沖區實現。
當我們調用pipe()函數創建管道時,需要傳入一個文件描述符數組,一個表示讀端,一個表示寫端。就好像一個管道一樣,寫方進程將數據寫入,讀方再通過管道將數據讀出。既然規定了讀和寫的兩端,以及是環形隊列以及緩沖區實現,就證明了有一定的局限性。
1.數據不可反復讀取,即讀了之後在緩沖區中就沒有了
2.半雙工通信,只能單方向的傳輸數據
3.有血緣關系的進程之間通信
創建管道的函數原型:int pipe(pipefd[2])
所需頭文件:#include
參數pipefd[2]會返回兩個文件描述符,一個用於讀,另一個用於寫。默認是fd[0]讀,fd[1]寫。如果創建管道成功,返回0,否則返回-1。
例子:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> int main() { int fd[2]; pid_t pid; if(pipe(fd) == -1) { perror("pipe error:"); exit(1); } pid = fork(); if(pid == -1) { perror("fork error:"); exit(2); } else if(pid == 0) //本例子中子進程寫數據 { close(fd[0]); //關閉讀數據的文件描述符 write(fd[1], "hello pipe!\n", strlen("hello pipe!\n")); //寫入數據 } else { close(fd[1]); char buf[102400]; int ret = read(fd[0], buf, sizeof(buf)); //通過管道讀出數據 if(ret == 0) { printf("讀到了文件末尾\n"); } write(STDOUT_FILENO, buf, ret); //輸出到終端 } return 0; } //輸出結果: hello pipe!
在使用管道時,有幾種特殊情況需要注意:
1.管道中沒有數據時,如果管道寫端全部關閉,那麼此時read函數會返回0,如果管道寫端沒有全部關閉,那麼此時read會阻塞等待數據。也就是說,在上面的例子中,如果子進程通過sleep函數睡眠10秒,父進程也會阻塞等待子進程寫數據,因為此時子進程的寫端仍處於開啟狀態。
2.管道讀端全部關閉,進程會異常終止(可以理解為讀數據的都沒有了,那寫數據也沒有意義了)
3.管道已滿時,寫入會阻塞。
要知道管道只能在有血緣關系的進程之間通信,而有名管道恰可以用於無血緣關系的進程間通信。