管道
管道是一种最基本的进程间通信机制,由pipe
函数创建:
#include <unistd.h>
int pipe(int filedes[2]);
调用pipe
函数时在内核中开辟一块缓冲区(称为管道)用于通信,它有一个读端一个写端,然后通过filedes
参数传出给用户程序两个文件描述符,filedes[0]
指向管道的读端,filedes[1]
指向管道的写端。向这个文件读写数据其实是在读写内核缓冲区。pipe
函数调用成功返回0,调用失败返回-1。
管道代码示例
子进程通过管道向父进程发送数据。限制在父子进程间通信。
#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;
}
两个进程通过一个管道只能实现单向通信,比如上面的例子,子进程写父进程读,如果有时候也需要父进程写子进程读,就必须另开一个管道。
命名管道
管道的使用有个限制,就是必须是父子进程间才可以通信,如果不是父子进程是不能使用上面的管道通信的,需要命名管道。
#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
标志):
-
如果所有指向管道写端的文件描述符都关闭了(管道写端的引用计数等于0),而仍然有进程从管道的读端读数据,那么管道中剩余的数据都被读取后,再次
read
会返回0,就像读到文件末尾一样。 -
如果有指向管道写端的文件描述符没关闭(管道写端的引用计数大于0),而持有管道写端的进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据都被读取后,再次
read
会阻塞,直到管道中有数据可读了才读取数据并返回。 -
如果所有指向管道读端的文件描述符都关闭了(管道读端的引用计数等于0),这时有进程向管道的写端
write
,那么该进程会收到信号SIGPIPE
,通常会导致进程异常终止。 -
如果有指向管道读端的文件描述符没关闭(管道读端的引用计数大于0),而持有管道读端的进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时再次
write
会阻塞,直到管道中有空位置了才写入数据并返回。
其实和其他I/O事件的阻塞与同步是一样的。
今天的文章Linux进程间通信——管道分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/14689.html