【问题标题】:Bad file descriptor error when closing pipe file descriptors after forking [closed]分叉后关闭管道文件描述符时出现错误的文件描述符错误[关闭]
【发布时间】:2021-03-12 07:09:30
【问题描述】:

我尝试让 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 (bad file descriptor)。

我的错误是什么?

【问题讨论】:

  • 您的代码没有错误检查或处理。你怎么知道你得到了那个错误?
  • 你调用了两次fork,所以现在你有四个进程。其中至少有一个正在尝试关闭管道[0] 两次。
  • @dratenik 你确定吗?似乎它关闭了孩子们的管道,不是吗?
  • @Shawn 是的,我也发现了,已修复 :) 我什至不确定它实际上是 0 还是 1,这段代码的咖啡量不够。
  • @thecorrectanswer OP 没有提到故障发生在哪里,我认为是其中一个孩子(可能同时执行了两个 if)。

标签: c unix pipe fork child-process


【解决方案1】:

首先,现有进程调用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);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-28
    • 2017-09-05
    • 2018-12-02
    相关资源
    最近更新 更多