fork() 和 wait() 有两个子进程

Posted

技术标签:

【中文标题】fork() 和 wait() 有两个子进程【英文标题】:fork() and wait() with two child processes 【发布时间】:2011-02-12 02:27:21 【问题描述】:

我需要使用fork()wait() 函数来完成作业。我们正在对非确定性行为进行建模,如果有多个可能的转换,则需要将程序发送到fork()

为了尝试弄清楚forkwait 是如何工作的,我刚刚编写了一个简单的程序。我想我现在明白了调用是如何工作的,如果程序只分支一次就可以了,因为父进程可以使用单个子进程的退出状态来确定子进程是否达到接受状态。

正如您从下面的代码中看到的那样,我希望能够处理必须有多个子进程的情况。我的问题是您似乎只能使用 _exit 函数设置一次状态。因此,在我的示例中,父进程测试的退出状态显示第一个子进程发出 0 作为其退出状态,但没有关于第二个子进程的信息。

我只是尝试不_exit()-ing 拒绝,但随后该子进程将继续,实际上似乎有两个父进程。

对于华夫饼感到抱歉,但如果有人能告诉我我的父进程如何获取多个子进程的状态信息,我将不胜感激,或者我很高兴父进程只从子进程,但在这种情况下,我需要成功退出具有拒绝状态的子进程。

我的测试代码如下:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/wait.h>

int main(void)  

    pid_t child_pid, wpid, pid;
    int status = 0;
    int i;

    int a[3] = 1, 2, 1;
    for(i = 1; i < 3; i++)  
        printf("i = %d\n", i);
        pid = getpid();
        printf("pid after i = %d\n", pid);
        if((child_pid = fork()) == 0)  
            printf("In child process\n");
            pid = getpid();
            printf("pid in child process is %d\n", pid);
            /* Is a child process */
            if(a[i] < 2)  
                printf("Should be accept\n");
                _exit(1);
             else  
                printf("Should be reject\n");
                _exit(0);
            
        
    

    if(child_pid > 0)  
        /* Is the parent process */
        pid = getpid();
        printf("parent_pid = %d\n", pid);
        wpid = wait(&status);
        if(wpid != -1)  
            printf("Child's exit status was %d\n", status);
            if(status > 0)  
                printf("Accept\n");
             else  
                printf("Complete parent process\n");
                if(a[0] < 2)  
                    printf("Accept\n");
                 else  
                    printf("Reject\n");
                
            
        
    
    return 0;

【问题讨论】:

【参考方案1】:

将您的 wait() 函数放入一个循环中并等待所有子进程。如果没有更多的子进程可用,等待函数将返回 -1 并且 errno 将等于 ECHILD。

【讨论】:

太棒了。我明白。非常感谢。【参考方案2】:

在我看来,基本问题似乎是你有一个wait() 调用,而不是一个等待直到没有更多孩子的循环。您也只等待最后一个fork() 成功而不是至少一个fork() 成功。

如果您不想进行正常的清理操作(例如刷新包括stdout 在内的打开文件流),则应仅使用_exit()。有场合使用_exit();这不是其中的一个。 (在这个例子中,当然,你也可以简单地让孩子们返回而不是直接调用exit(),因为从main()返回相当于以返回状态退出。但是,大多数情况下你会做分叉和在main() 以外的函数中以此类推,然后exit() 通常是合适的。)


提供我想要的诊断的代码的黑客简化版本。请注意,您的 for 循环跳过了数组的第一个元素(我的没有)。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>

int main(void)

    pid_t child_pid, wpid;
    int status = 0;
    int i;
    int a[3] = 1, 2, 1;

    printf("parent_pid = %d\n", getpid());
    for (i = 0; i < 3; i++)
    
        printf("i = %d\n", i);
        if ((child_pid = fork()) == 0)
        
            printf("In child process (pid = %d)\n", getpid());
            if (a[i] < 2)
            
                printf("Should be accept\n");
                exit(1);
            
            else
            
                printf("Should be reject\n");
                exit(0);
            
            /*NOTREACHED*/
        
    

    while ((wpid = wait(&status)) > 0)
    
        printf("Exit status of %d was %d (%s)\n", (int)wpid, status,
               (status > 0) ? "accept" : "reject");
    
    return 0;

示例输出(MacOS X 10.6.3):

parent_pid = 15820
i = 0
i = 1
In child process (pid = 15821)
Should be accept
i = 2
In child process (pid = 15822)
Should be reject
In child process (pid = 15823)
Should be accept
Exit status of 15823 was 256 (accept)
Exit status of 15822 was 0 (reject)
Exit status of 15821 was 256 (accept)

【讨论】:

好的。我明白。非常感谢您的回复。 再次感谢您的宝贵时间。那太棒了。在你最初的帖子之后,我制作了一个我自己的受损工作版本,但你的更整洁。干杯 @Joe 如果此回复对您最有帮助,那么您应该点击左侧的复选标记接受它。 @Richard:我想过这个问题,但是由于问题指出这是一个整理进程间同步细节的精简示例,我得出结论,这不是在喂食答案到家庭作业。 @Jonathan:我只是在开玩笑......这是一个很好的问题,而你的问题是一个很好的答案。【参考方案3】:

出色的示例 Jonathan Leffler,为了让您的代码在 SLES 上运行,我需要添加一个额外的标头以允许 pid_t 对象:)

#include <sys/types.h>

【讨论】:

这很奇怪...POSIX 2008 和我遇到的所有其他 Linux 系统都不需要 &lt;sys/types.h&gt; 标头。 &lt;unistd.h&gt; 中的一些函数(例如getpid())在其声明中需要类型,因此&lt;sys/types.h&gt; 不需要显式包含。你能说明你使用的编译器选项需要#include &lt;sys/types.h&gt;吗? @JonathanLeffler 我知道这是一条旧评论,但 SLES 比其他评论更老。这就像 RedHat 的 EL。所以这就是我猜的原因。

以上是关于fork() 和 wait() 有两个子进程的主要内容,如果未能解决你的问题,请参考以下文章

子进程子回溯

golang 热重启

linux进程原语之fork()(原创!)

shell多进程实例

linux c学习笔记----进程创建(fork,wait,waitpid)

fork,wait和exec