管道是一種最基本的進程間通訊機制,由pipe
函數建立:函數
#include <unistd.h>
int pipe(int filedes[2]);
複製代碼
調用pipe
函數時在內核中開闢一塊緩衝區(稱爲管道)用於通訊,它有一個讀端一個寫端,而後經過filedes
參數傳出給用戶程序兩個文件描述符,filedes[0]
指向管道的讀端,filedes[1]
指向管道的寫端。向這個文件讀寫數據實際上是在讀寫內核緩衝區。pipe
函數調用成功返回0,調用失敗返回-1。ui
子進程經過管道向父進程發送數據。限制在父子進程間通訊。spa
#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<string.h>
int main () {
char* msg;
char buf[20];
int pipe_filed[2];
pipe(pipe_filed);
pid_t pid = fork();
if(pid < 0) {
perror("fork errir.");
exit(1);
} else if (0 == pid) {
msg = "child";
write(pipe_filed[1], msg, sizeof(msg));
printf("child process send: %s\n", msg);
} else {
read(pipe_filed[0], buf, sizeof(buf));
printf("parent process recv: %s\n", buf);
int status;
wait(&status);
if (WIFEXITED(status))
printf("Child exited with code %d\n", WEXITSTATUS(status));
else if (WIFSIGNALED(status))
printf("Child terminated abnormally, signal %d\n", WTERMSIG(status));
}
return 0;
}
複製代碼
兩個進程經過一個管道只能實現單向通訊,好比上面的例子,子進程寫父進程讀,若是有時候也須要父進程寫子進程讀,就必須另開一個管道。code
管道的使用有個限制,就是必須是父子進程間才能夠通訊,若是不是父子進程是不能使用上面的管道通訊的,須要命名管道。orm
#include<sys/types.h>
#include<sys/stat.h>
int mkfifo(const char * pathname,mode_t mode);
複製代碼
依參數pathname
創建特殊的FIFO
文件,參數mode
爲該文件的權限。若成功則返回0,不然返回-1,錯誤緣由存於errno
中。進程
沒必要是父子進程間。進程A向進程B發送信息:事件
/* send process*/
#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<string.h>
int main () {
if (-1 == mkfifo("comm", 0666)) {
if (EEXIST != errno) {
perror("mkfifo failure.");
exit(EXIT_FAILURE);
}
}
int fd = open("comm", O_WRONLY);
if (fd < 0) {
perror("open pipe failure.");
}
char* msg = "process of send.";
write(fd, msg, strlen(msg));
close(fd);
return 0;
}
複製代碼
/* recv process*/
#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<errno.h>
#include<string.h>
int main () {
if (-1 == mkfifo("comm", 0666)) {
if (EEXIST != errno) {
perror("mkfifo failure.");
exit(EXIT_FAILURE);
}
}
int fd = open("comm", O_RDONLY);
if (fd < 0) {
perror("open pipe failure.");
}
char* buf = (char*)malloc(80);
bzero(buf, 80);
read(fd, buf, 80);
printf("recv from other process: %s\n", buf);
close(fd);
free(buf);
return 0;
}
複製代碼
使用管道須要注意如下4種特殊狀況(假設都是阻塞I/O操做,沒有設置O_NONBLOCK
標誌):ip
若是全部指向管道寫端的文件描述符都關閉了(管道寫端的引用計數等於0),而仍然有進程從管道的讀端讀數據,那麼管道中剩餘的數據都被讀取後,再次read
會返回0,就像讀到文件末尾同樣。同步
若是有指向管道寫端的文件描述符沒關閉(管道寫端的引用計數大於0),而持有管道寫端的進程也沒有向管道中寫數據,這時有進程從管道讀端讀數據,那麼管道中剩餘的數據都被讀取後,再次read
會阻塞,直到管道中有數據可讀了纔讀取數據並返回。string
若是全部指向管道讀端的文件描述符都關閉了(管道讀端的引用計數等於0),這時有進程向管道的寫端write
,那麼該進程會收到信號SIGPIPE
,一般會致使進程異常終止。
若是有指向管道讀端的文件描述符沒關閉(管道讀端的引用計數大於0),而持有管道讀端的進程也沒有從管道中讀數據,這時有進程向管道寫端寫數據,那麼在管道被寫滿時再次write
會阻塞,直到管道中有空位置了才寫入數據並返回。
其實和其餘I/O事件的阻塞與同步是同樣的。