管道是一种最基本的进程间通讯机制,由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事件的阻塞与同步是同样的。