分叉后关闭管道文件描述符时出现错误的文件描述符错误
Bad file descriptor error when closing pipe file descriptors after forking
我尝试让进程的 2 个子进程进行通信:
void demo() {
int pipes[2];
int create_pipe_status = pipe(pipes);
int status;
pid_t fork_id = fork();
if(!fork_id) {
//parent
status = dup2(pipes[1], STDOUT_FILENO);
close(pipes[0]);
close(pipes[1]);
}
pid_t fork_id2 = fork();
if(!fork_id2){
//child
status = dup2(pipes[0], STDIN_FILENO);
close(pipes[0]);
close(pipes[1]); //keep
}
wait(NULL);
wait(NULL);
}
当我尝试关闭与管道关联的文件描述符时,我在 errno
中收到错误 EBADF
( 错误的文件描述符)。
我的错误是什么?
首先,现有进程调用 fork()
,然后这个原始进程及其派生的子进程再次调用 fork()
,总共有四个进程。即进程为:
- 原来的流程。
- 原始进程的第一个子进程 - 由原始进程第一次调用
fork()
创建。
- 原始进程的第二个子进程 - 由原始进程第二次调用
fork()
创建。
- 子进程的子进程-由子进程第二次调用
fork()
创建。
因此,代码块(即第二个if
块)被子进程的子进程执行:
if(!fork_id2){
//child
status = dup2(pipes[0], STDIN_FILENO);
close(pipes[0]);
close(pipes[1]);
}
子进程的这个子进程试图关闭pipe[0]
和pipe[1]
。但是,子进程(即子进程的子进程的父进程)已经关闭了pipe[0]
和pipe[1]
。这就是坏文件描述符错误的来源,即关闭文件描述符两次。
请注意,即使原始进程的第二个子进程也执行此代码块,但它不会遇到此问题,因为原始进程在调用时尚未关闭管道文件描述符fork()
第二次,所以当原始进程的第二个子进程关闭它们时,两个文件描述符仍然打开。
我猜你真正想要的是两个从现有进程创建两个子进程。如果是这样,那么只需将对 fork()
的第二次调用限制为父进程(即原始进程):
void demo() {
int pipes[2];
int create_pipe_status = pipe(pipes);
int status;
pid_t fork_id = fork();
if (!fork_id) { // 1st child
status = dup2(pipes[1], STDOUT_FILENO);
assert(!close(pipes[0]));
assert(!close(pipes[1]));
} else {
// parent
pid_t fork_id2 = fork();
if (!fork_id2) { // 2nd child
status = dup2(pipes[0], STDIN_FILENO);
assert(!close(pipes[0]));
assert(!close(pipes[1]));
} else { // parent
assert(!close(pipes[0]));
assert(!close(pipes[1]));
}
}
wait(NULL);
wait(NULL);
}
我尝试让进程的 2 个子进程进行通信:
void demo() {
int pipes[2];
int create_pipe_status = pipe(pipes);
int status;
pid_t fork_id = fork();
if(!fork_id) {
//parent
status = dup2(pipes[1], STDOUT_FILENO);
close(pipes[0]);
close(pipes[1]);
}
pid_t fork_id2 = fork();
if(!fork_id2){
//child
status = dup2(pipes[0], STDIN_FILENO);
close(pipes[0]);
close(pipes[1]); //keep
}
wait(NULL);
wait(NULL);
}
当我尝试关闭与管道关联的文件描述符时,我在 errno
中收到错误 EBADF
( 错误的文件描述符)。
我的错误是什么?
首先,现有进程调用 fork()
,然后这个原始进程及其派生的子进程再次调用 fork()
,总共有四个进程。即进程为:
- 原来的流程。
- 原始进程的第一个子进程 - 由原始进程第一次调用
fork()
创建。 - 原始进程的第二个子进程 - 由原始进程第二次调用
fork()
创建。 - 子进程的子进程-由子进程第二次调用
fork()
创建。
因此,代码块(即第二个if
块)被子进程的子进程执行:
if(!fork_id2){
//child
status = dup2(pipes[0], STDIN_FILENO);
close(pipes[0]);
close(pipes[1]);
}
子进程的这个子进程试图关闭pipe[0]
和pipe[1]
。但是,子进程(即子进程的子进程的父进程)已经关闭了pipe[0]
和pipe[1]
。这就是坏文件描述符错误的来源,即关闭文件描述符两次。
请注意,即使原始进程的第二个子进程也执行此代码块,但它不会遇到此问题,因为原始进程在调用时尚未关闭管道文件描述符fork()
第二次,所以当原始进程的第二个子进程关闭它们时,两个文件描述符仍然打开。
我猜你真正想要的是两个从现有进程创建两个子进程。如果是这样,那么只需将对 fork()
的第二次调用限制为父进程(即原始进程):
void demo() {
int pipes[2];
int create_pipe_status = pipe(pipes);
int status;
pid_t fork_id = fork();
if (!fork_id) { // 1st child
status = dup2(pipes[1], STDOUT_FILENO);
assert(!close(pipes[0]));
assert(!close(pipes[1]));
} else {
// parent
pid_t fork_id2 = fork();
if (!fork_id2) { // 2nd child
status = dup2(pipes[0], STDIN_FILENO);
assert(!close(pipes[0]));
assert(!close(pipes[1]));
} else { // parent
assert(!close(pipes[0]));
assert(!close(pipes[1]));
}
}
wait(NULL);
wait(NULL);
}