【问题标题】:Only one child out of the many children die and the rest wait for ctrl + c许多孩子中只有一个孩子死了,其余的等待 ctrl + c
【发布时间】:2017-11-03 07:27:27
【问题描述】:

我正在为 Linux 中的 C 语言编写 shell 代码,我必须在其中实现多个管道(例如 A | B | c | D,其中 A、B、C、D 是命令)。 shell 为每个具有相同 pgid 的命令创建一个单独的进程,并使用 pipe() 系统调用连接它们的输入和输出。一旦创建了所有的孩子,父母使用 tcsetpgrp() 使这个 pgid 进入前台并进入后台。一切正常,但事实上,一旦执行 A、B、C、D 的孩子完成,只有处理 A 的 child1 死亡并由 sigchild 处理程序处理,其他孩子只是等待,什么也不做,直到我按下 ctrl + c。一旦 ctrl + c 被按下,所有其他的孩子都会被信号处理程序收割,并且处于 sigsuspend 中的父母会醒来并再次回到前台。

谁能帮我理解为什么只有孩子 1 死了,控制在哪里,而其他孩子没有完成?

这是 SIGINT 处理程序的代码。

void sigchld_handler(int s) {

int olderrno = errno;
sigset_t mask_all;
sigset_t prev_all;

sigfillset(&mask_all);
while ((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
    sigprocmask(SIG_BLOCK, &mask_all, &prev_all);
    NoOfChildrenToBeReaped--;
    sigprocmask(SIG_SETMASK, &prev_all, NULL);
}
errno = olderrno;

}

这是父级创建所需数量的子级后的代码。

//Get the pid of the first child and set it as the pgid of all the sibling children.
if (i == 0) {
    pgid = pid;
}
setpgid(pid, pgid);

这是父进程进入后台的过程,跟踪有多少孩子将被收割,并在 sigsuspend() 之后返回前台。

if (BGProc) {
    if (tcsetpgrp(STDIN_FILENO, pgid) == -1) {
        printf(EXEC_ERROR, "Error in tcsetpgrp");
    }

    while (NoOfChildrenToBeReaped) {
        sigsuspend(&masknone);
    }

    signal(SIGTTOU, SIG_IGN);
    if (tcsetpgrp(STDIN_FILENO, getpid()) == -1) {
        printf(EXEC_ERROR, "Error in tcsetpgrp");
    }
}

非常感谢任何帮助。

谢谢。

【问题讨论】:

  • 孩子A为什么会死?因为过程结束了?然后,从标准输入读取的下一个子 B 也应该获得 EOF 并终止自身。现在,由于这没有发生,很可能管道的写入端,A 写入和 B 读取的管道没有关闭。在 fork 孩子之后,您是否在主进程(以及所有其他进程,如果适用)中正确关闭了写作端?不幸的是,您没有显示那部分代码。
  • 是的,子 A 完成了它的工作并正常终止。我确信管道已正确关闭。我很想添加这部分代码,但它非常庞大并且是作业的一部分。我不确定我可以在这里发布多少。
  • 在系统环境中,在进程a终止后跟踪进程b(使用strace)。它挂在哪里?
  • 感谢您的宝贵反馈。这确实是没有正确关闭管道 fds 的问题。我以为我已经正确关闭了它,但我正在使用迭代器 i 循环并关闭 pipefds[j]。 :-X。解决了这个问题。
  • "许多孩子中只有一个孩子死了,其余的等待 ctrl + c" -- 非程序员会认为这是一个非常悲伤的故事。 8-)}

标签: c linux shell pipe sigint


【解决方案1】:

这实际上是一个愚蠢的错误,而且确实是一个问题,因为用于管道的 FileDescriptor 没有正确关闭。感谢@Ctx 指出并通过 cmets 提出好的建议。

for (i = 0; i < 2 * NoOfPipes; i++)
    close(pipefds[j]); //should have been "i".

我想我忽略了“for”中的代码并认为这是理所当然的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-07
    • 1970-01-01
    • 2016-11-30
    • 2021-04-28
    • 2012-09-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多