在 C(不是 C++)中使用 fork() 从 1 parent 中生成 3 children

using fork() to make 3 children out of 1 parent in C (not C++)

您好,我一直在开发一个程序,该程序可以分叉 children,稍后将从每个 child 中分叉出更多 children,但这不是我需要帮助的。当我 运行 我的程序(在这里它是一个函数但工作相同)我应该有一个 parent(PPID) spawn 3 children (PIDS= 1,2, 3) 但是我得到的是相同的 PID 和 PPID 3 次(我当前的代码)或者在我得到 3 parents 之前每个 parent 有一个 child 并且 PPIDS 是与 PIDS 不同,但 PPID 与之前的 child PID 相同。在我最近的尝试中,它从不在 child(son) 上方显示 parent(dad) 消息。它应该是这样的

[dad] hi am I PID 1234 and I come from ####(dont care what this number is)
[son] hi i am PID 1111 and I come from PPID 1234
[son] hi i am PID 1112 and I come from PPID 1234
[son] hi i am PID 1113 and I come from PPID 1234

这是我的代码。如果可能的话,我只是在寻找提示,除非它只是我犯的一个愚蠢的错误,例如 "oh just move the fork() to the child process" 或类似的错误。

我还有一个child_count,所以我可以很容易地数出children。

 int forking(null)
{
       void about(char *);
        int i=0;
        int j=0;
        int child_count =0;
        about("dad");

    for(i = 0; i < 3; i++ ){
        pid_t child = 0;
        child = fork();


            if (child < 0) { //unable to fork error
                    perror ("Unable to fork");
                    exit(-1);}

           else if (child == 0){ //child process
                    about ("son");
                    printf("I am child #%d \n",child_count);
                    child_count++;
                    exit(0);}

            else { //parent process (do nothing)

                }
            }

                for(j = 0; j < 3; j++ ){
                            wait(NULL);//wait for parent to acknowledge child process
                            }
return 0;
}

您必须记住的一件事是,当您 fork 时,parent 和 child 都将继续 运行 那个时候的代码.

所以,如果你没有正确地进行 child/parent 检测,children 很可能会启动他们自己的 child任.

启动三个 children 而没有 grandchildren 的一个好方法是将计数器与 fork 调用返回的进程 ID 结合使用,按照以下内容:

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

#define COUNT 3

int main(void) {
    # Desired and actual count.

    int count = COUNT, children = 0;

    // Force parent initially.

    pid_t retpid = 1;

    // Only fork if limit not reached AND is parent (children
    //   will exit loop with retpid == 0).

    while (count-- > 0 && retpid > 0)
        // Adjust actual count if successful.

        if ((retpid = fork()) > 0)
            children++;

    // Detect parent, all forks returned non-zero.

    if (retpid != 0) {
        printf("Parent %d spawned %d/%d children\n",
            getpid(), children, COUNT);

        // Wait for children to finish.

        while (children-- > 0)
            wait(NULL);
    } else {
        // Otherwise you were one of the children.

        printf("Child %d, sired by %d\n", getpid(), getppid());
    }

    return 0;
}

由于日程安排的变幻莫测,这输出了你似乎想要的东西,而不是必须的顺序:

Parent 26210 successfully spawned 3/3 children
Child 26212, sired by 26210
Child 26213, sired by 26210
Child 26211, sired by 26210

检查返回的 PID 将确保只有 parent 进行任何分叉,并且计数将其限制在特定数量。


您还需要注意的一件事是输出缓冲。分叉时,您可能会得到两个带有缓冲输出数据的进程。

在可以检测到输出设备是终端的情况下,刷新通常会发生在正在输出的换行符上,因此您的 printf 调用可能不会复制正常 运行 的输出。

您只需要注意,例如,如果您将输出重定向到一个文件,您可能会得到 有趣的 结果。

parent需要
- 打印一条消息
- 三声叉子
- 等待三children退出

每个child需要
- 打印一条消息
- 退出

所以代码就这么简单

int main( void )
{
    printf( "[dad] pid %d\n", getpid() );

    for ( int i = 0; i < 3; i++ )
        if ( fork() == 0 )
        {
            printf( "[son] pid %d from pid %d\n", getpid(), getppid() );
            exit( 0 );
        }

    for ( int i = 0; i < 3; i++ )
        wait( NULL );
}

生成此输出

[dad] pid 1777
[son] pid 1778 from pid 1777
[son] pid 1779 from pid 1777
[son] pid 1780 from pid 1777