为什么fork()返回值为-1,为什么wait()退出状态不为0?

时间:2015-01-31 23:22:45

标签: c multiprocessing fork

在该计划中:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    int pid;
    int status;

    pid = fork();

    if (pid < 0)
    {
        return -1;
    }
    else if (pid == 0)
    {
        printf("I am the child\n");
        exit(0);
    }
    else if (pid > 0)
    {
        pid = wait(&status);
        printf("I am the parent\n");
        printf("My pid is %i\nMy childs's pid is %i\nMy childs's exit status is     %i\n", getpid(), pid, status);

    }

}

该程序返回:

I am the child
I am the parent
My pid is 16269
My childs's pid is -1
My childs's exit status is 32767

1)为什么孩子的pid = -1而不是实际的子进程号?

2)为什么孩子的退出状态!= 0,如我所愿?

2 个答案:

答案 0 :(得分:3)

关于子进程ID,因为您重新分配了pid变量,并且wait会在出错时返回-1

关于退出状态,由于wait失败,它无效。但除此之外,它只包含包含实际状态的八个最低位。首先,您需要确保wait调用确实成功,然后您需要使用WIFEXITED宏检查进程是否正常退出,然后使用WEXITSTATUS获取实际退出状态宏。

我建议您阅读wait<sys/wait.h>标头文件的参考资料。

答案 1 :(得分:2)

诊断

我认为您必须在忽略SIGCHLD信号的情况下运行该过程。

当我正常运行你的代码时,我得到输出,如:

$ ./wp0
I am the child
I am the parent
My pid is 80161
My childs's pid is 80162
My childs's exit status is     0
$

但是,如果我在忽略SIGCHLD信号的情况下运行它,我会得到:

$ (trap '' CHLD; ./wp0)
I am the child
I am the parent
My pid is 80435
My childs's pid is -1
My childs's exit status is     0
$

您可以通过在shell命令行运行'trap'来检查这一点。例如,我得到:

$ (trap '' CHLD; trap)
trap -- '' SIGCHLD
$

如果使用trap(没有参数)没有产生类似的答案,那么您可能需要编写一个程序来询问SIGCHLD状态。

顺便提一下,我做的第一件事(在回到原始代码之前)是将父代码更改为:

    int corpse = wait(&status);
    printf("I am the parent\n");
    printf("My pid is %i\nMy child's pid was %i\nMy child's exit status is %i\n", getpid(), pid, status);
    printf("My child's corpse was %i\n", corpse);

它从wait()的返回值中单独捕获fork()的返回值。此外,我通常使用0x%.4X打印退出状态 - 部分原因是因为我对十六进制值的格式保持肛门,但主要是因为十六进制值更容易理解。您可以尝试使用不同的值(可能解释命令行参数)退出子项,甚至可以使用不同的信号自杀。虽然WIFEXITEDWEXITSTATUSWIFSIGNALEDWTERMSIG等宏都很好,但它们也非常简单,您可以通过查看十字架{{{{{{ 1}}。

为退出状态和信号创建试验台

我扩展了您的程序以创建一个有效的测试工具,允许您尝试退出值和信号处理,如下所示:

status

我打电话给程序#include <errno.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/wait.h> #include <unistd.h> int main(int argc, char **argv) { int c_status = 0; int c_signal = 0; int opt; while ((opt = getopt(argc, argv, "s:e:")) != EOF) { switch (opt) { case 's': c_signal = atoi(optarg); break; case 'e': c_status = atoi(optarg); break; default: fprintf(stderr, "Usage: %s [-e status][-s signal]", argv[0]); exit(EXIT_FAILURE); } } sigset_t oset; if (pthread_sigmask(SIG_BLOCK, 0, &oset) != 0) { fprintf(stderr, "%s: pthread_sigmask() failed (%d: %s)\n", argv[0], errno, strerror(errno)); exit(EXIT_FAILURE); } if (sigismember(&oset, SIGCHLD)) printf("SIGCHLD is listed in the signal mask\n"); struct sigaction oact; if (sigaction(SIGCHLD, 0, &oact) != 0) { fprintf(stderr, "%s: pthread_sigmask() failed (%d: %s)\n", argv[0], errno, strerror(errno)); exit(EXIT_FAILURE); } if (oact.sa_handler == SIG_DFL) printf("SIGCHLD handling is the default\n"); else if (oact.sa_handler == SIG_IGN) printf("SIGCHLD handling is ignoring the signal\n"); else printf("SIGCHLD has a signal handler installed (%p)\n", (void *)oact.sa_handler); if (oact.sa_flags & SA_NOCLDSTOP) printf("SA_NOCLDSTOP is set\n"); if (oact.sa_flags & SA_NOCLDWAIT) printf("SA_NOCLDWAIT is set\n"); int pid = fork(); if (pid < 0) { return -1; } else if (pid == 0) { printf("I am the child - PID %d\n", (int)getpid()); if (c_signal == 0) { printf("I am exiting with status %d\n", c_status); exit(c_status); } else { printf("I am committing suicide with signal %d\n", c_signal); raise(c_signal); printf("That didn't work - I'm still here. Oh well!\n"); exit(EXIT_FAILURE); } } else if (pid > 0) { int status; int corpse = wait(&status); printf("I am the parent\n"); printf("My pid is %i\n", getpid()); printf("My child's pid was %i\n", pid); printf("My child's corpse was %i\n", corpse); printf("My child's exit status is 0x%.4X\n", status); if (WIFEXITED(status)) printf("My child exited normally with status %d\n", WEXITSTATUS(status)); if (WIFSIGNALED(status)) { printf("My child died from signal %d\n", WTERMSIG(status)); #ifdef WCOREDUMP if (WCOREDUMP(status)) printf("My child produced a core dump\n"); #endif } } return 0; } 。用不同的选项运行它几次给出如下输出:

wp2

易于解释原始状态这一事实并不是避免使用POSIX提供的宏的借口。请注意,POSIX未指定$ ulimit -c unlimited $ ./wp2 -s 4 SIGCHLD handling is the default I am the child - PID 81188 I am committing suicide with signal 4 I am the parent My pid is 81187 My child's pid was 81188 My child's corpse was 81188 My child's exit status is 0x0004 My child died from signal 4 $ ./wp2 -s 6 SIGCHLD handling is the default I am the child - PID 81224 I am committing suicide with signal 6 I am the parent My pid is 81223 My child's pid was 81224 My child's corpse was 81224 My child's exit status is 0x0086 My child died from signal 6 My child produced a core dump $ ulimit -c 0 $ ./wp2 -s 6 SIGCHLD handling is the default I am the child - PID 81489 I am committing suicide with signal 6 I am the parent My pid is 81488 My child's pid was 81489 My child's corpse was 81489 My child's exit status is 0x0006 My child died from signal 6 $ (trap '' CHLD; ./wp2 -s 6) SIGCHLD handling is ignoring the signal SA_NOCLDWAIT is set I am the child - PID 82300 I am committing suicide with signal 6 I am the parent My pid is 82299 My child's pid was 82300 My child's corpse was -1 My child's exit status is 0x0000 My child exited normally with status 0 $ ./wp2 -e 6 SIGCHLD handling is the default I am the child - PID 82434 I am exiting with status 6 I am the parent My pid is 82433 My child's pid was 82434 My child's corpse was 82434 My child's exit status is 0x0600 My child exited normally with status 6 $ ,但通常可用。