c - 管道:关闭管道数组中的文件描述符
问题描述
我现在正在为我的系统编程课程学习 Linux 和管道那些东西,我现在很难理解在管道数组中关闭文件描述符。
// write the code to loop over the command line arguments (remember to skip the executable name)
for (int i = 1; i < argc; i++) {
// call pipe before we fork
if ((pipe(pipe_fd[i-1])) == -1) {
perror("pipe");
exit(1);
}
// call fork
int result = fork();
if (result < 0) { // case: a system call error
// handle the error
perror("fork");
exit(1);
} else if (result == 0) { // case: a child process
// child does their work here
// child only writes to the pipe so close reading end
if (close(pipe_fd[i-1][0]) == -1) {
perror("close reading end from inside child");
exit(1);
}
// before we forked the parent had open the reading ends to
// all previously forked children -- so close those
int child_no;
for (child_no = 0; child_no < i-1; child_no++) {
if (close(pipe_fd[child_no][0]) == -1) {
perror("close reading ends of previously forked children");
exit(1);
}
}
int len = strlen(argv[i]);
// write len to the pipe as an integer
if (write(pipe_fd[i-1][1], &len, sizeof(int)) != sizeof(int)) {
perror("write from child to pipe");
exit(1);
}
// I'm done with the pipe so close it
if (close(pipe_fd[i-1][1]) == -1) {
perror("close pipe after writing");
exit(1);
}
// exit so I don't fork my own children on next loop iteration
exit(0);
} else {
// in the parent but before doing the next loop iteration
// close the end of the pipe that I don't want open
if (close(pipe_fd[i-1][1]) == -1) {
perror("close writing end of pipe in parent");
exit(1);
}
}
}
我将列出我现在理解的内容:
- 我了解父子进程需要关闭那些他们不需要使用的 fd,在这种情况下子进程正在写入父进程,所以父进程需要关闭写入端口,子进程需要关闭读取端口。
- 我了解文件描述符在父进程和子进程之间共享。
上面的代码是从我的演讲幻灯片中给出的,我特别对一件事感到困惑。
在循环中,我观察到一旦这个孩子被 fork 创建,每个孩子都会关闭其阅读端口,执行此操作的代码是:
else if (result == 0) { // case: a child process
// child does their work here
// child only writes to the pipe so close reading end
if (close(pipe_fd[i-1][0]) == -1) {
perror("close reading end from inside child");
exit(1);
}
从我目前的理解来看,每个孩子出生后都会关闭自己的阅读端口,我认为后一个孩子创建的应该不担心关闭以前的孩子的阅读端口。
但是在我阅读了这段代码后,我的理解似乎并不正确:
// before we forked the parent had open the reading ends to
// all previously forked children -- so close those
int child_no;
for (child_no = 0; child_no < i-1; child_no++) {
if (close(pipe_fd[child_no][0]) == -1) {
perror("close reading ends of previously forked children");
exit(1);
}
}
我不明白为什么后面的孩子要关闭以前的孩子的阅读端口,一旦这些孩子被创建,那些阅读端口不是已经关闭了吗?
谢谢你的协助。:)
解决方案
一个描述符直到所有打开它的进程都关闭它才真正关闭。由于每个子进程都继承了前一个进程的所有管道描述符,因此他们应该关闭所有不使用的管道描述符。
关闭读取端口的主要原因是,如果在读取器退出后尝试写入管道,写入过程会收到错误或信号。如果其他孩子保持所有阅读端口打开,则在所有后续孩子退出之前不会发生这种情况。
推荐阅读
- python - How do I upgrade pandas using Anaconda?
- firebase - Flutter:如何在 Flutter 中创建嵌套对象以存储在 Cloud Firestore
- python - 如何提取文本文件中所有行的某些部分?
- ios - 在使用 Mac 终端时根据文件名更改创建日期和时间
- bash - “异步”检查远程更改?
- tmux - C-: 可以绑定在 tmux 中吗?
- java - 如何配置 Spring 集成适配器以通过 SFTP 获取和放置文件
- java - 使用 VSCode 调试多模块 maven 项目的正确方法是什么?
- python - 从文件列表中输出时间戳
- html - 将 tabindex 设置为角度材料元素