Warm tip: This article is reproduced from serverfault.com, please click

c-在分叉后关闭管道文件描述符时出现错误的文件描述符错误

(c - Bad file descriptor error when closing pipe file descriptors after forking)

发布于 2020-11-30 10:58:40

我尝试让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);
}

当我尝试关闭与管道关联的文件描述符时,出现错误EBADF错误的文件描述符errno

我怎么了

Questioner
Mr P
Viewed
0
ローウ 2020-11-30 19:35:22

首先,现有流程调用fork(),然后此原始流程及其派生的子fork()流程再次调用,总共产生四个流程。即,这些过程是:

  1. 原始过程。
  2. 原始流程的第一个子对象-由原始流程在第一次调用时创建的fork()
  3. 原始流程的第二个子级-由原始流程通过第二次调用来创建fork()
  4. 子进程的子进程–由子进程创建,并第二次调用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);
}