【问题标题】:No Child Process Error from waitpid() when waiting for process group等待进程组时waitpid()没有子进程错误
【发布时间】:2009-10-22 15:26:37
【问题描述】:

编写我自己的玩具外壳,但在尝试实现作业控制时遇到了麻烦。

我正在使用 setpgid 在子进程和父进程中设置子进程组。我的等待电话是:

pid = waitpid(-pid, &status, 0)

但是,waitpid 返回 -1 并且 perror 说“没有子进程”。但是,它似乎每次都在等待。此外, ps 输出看起来正确意味着从 shell 运行时。由于 ps parent 的进程是 kbsh ,就像我期望的那样。

% ps -o pid,ppid,pgrp,session,tpgid,comm
Forking
In Parent: Setting process group to 20809 of process 20809 with setpgid
In Child Processes, pid of child process is 20809
in Child: Setting process group to 20809 of process 20809 with setpgid
Requesting that Process Group 20809 becomes the foreground process with tcsetpgrp
Waiting for job with process group 20809
  PID  PPID  PGRP  SESS TPGID COMMAND
12002 32573 12002 12002 20809 zsh
20808 12002 20808 12002 20809 kbsh
20809 20808 20809 12002 20809 ps
Wait Error: No child processes
Restoring Shell process group 20808 to forground

有人看到我做错了吗?如果需要可以发布更多代码...

【问题讨论】:

  • 似乎发生在 -1 和 -pid 上
  • 忽略了 SIGCHILD,这就是它不起作用的原因:-P

标签: c unix


【解决方案1】:

我忽略了 sigchld,来自 waitpid 手册页:

POSIX.1-2001 规定,如果 SIGCHLD 的处置设置为 SIG_IGN 或 SA_NOCLDWAIT 标志是 为 SIGCHLD 设置(参见 sigaction(2)), 那么终止的孩子不会 成为僵尸并调用 wait() 或 waitpid() 将阻塞直到所有 孩子已经终止,然后 失败,errno 设置为 ECHILD。( 原始的 POSIX 标准离开了 将 SIGCHLD 设置为的行为 SIG_IGN 未指定。)Linux 2.6 符合本规范。 但是,Linux 2.4(及更早版本)确实 not:如果 wait() 或 waitpid() 调用是 在忽略 SIGCHLD 时进行, 呼叫的行为就像 SIGCHLD 没有被忽略,即 是,调用阻塞直到下一个 child 终止,然后返回 该子进程的进程 ID 和状态。

【讨论】:

  • 感谢您回答这个问题,因为here 的文章似乎已经过时了。
【解决方案2】:

我在尝试为我的计算机科学课程实现一个小外壳时发现了这个线程,并想我会分享对我有用的东西。我收到以下错误:

Waitpid error: No child processes

就我而言,我使用的是计算机系统提供的包装器: 程序员视角教科书。为了解决我的错误,我将Waitpid 中的csapp.c 更改为

pid_t Waitpid(pid_t pid, int *iptr, int options) 
{
    pid_t retpid;

    if ((retpid  = waitpid(pid, iptr, options)) < 0) 
        unix_error("Waitpid error");
    return(retpid);
}

pid_t Waitpid(pid_t pid, int *iptr, int options)
{
        pid_t retpid;

        retpid  = waitpid(pid, iptr, options);
        if (retpid < 0 && errno != ECHILD)
                unix_error("Waitpid error");
        return(retpid);
}

【讨论】:

    【解决方案3】:

    您不必设置进程组 ID。孩子默认继承父母的pid作为组。 等待的时候,需要等待父母的pid:

    int main(int argc, char **argv)
    {
        pid_t pid;
        int stat;
    
        if ((pid = fork()))
        {
            printf("PARENT: %d | CHILD: %d\n", getpid(), pid);
            waitpid(-getpid(), &stat, 0);
            printf("DONE: %m\n");
        }
        else
        {
            printf("CHILD: %d\n", getpid());
            sleep(3);
        }
        return 0;
    }
    

    【讨论】:

    • gnu.org/s/libc/manual/html_node/… -- 好像说我愿意。 "由于每个进程都被分叉,它应该通过调用 setpgid 将自己放入新的进程组中"
    • 我认为是因为进程组是如何控制前台和后台的。
    猜你喜欢
    • 2020-01-15
    • 2020-09-09
    • 2020-08-30
    • 1970-01-01
    • 2015-02-24
    • 2012-07-02
    • 1970-01-01
    • 2017-09-15
    相关资源
    最近更新 更多