【问题标题】:using fork() to make 3 children out of 1 parent in C (not C++)使用 fork() 从 C 中的 1 个父级中生成 3 个子级(不是 C++)
【发布时间】:2015-12-26 12:35:37
【问题描述】:

您好,我一直在开发一个 fork 孩子的程序,然后会从每个孩子那里派生更多的孩子,但这不是我需要帮助的。当我运行我的程序时(在这里它是一个函数但工作方式相同)我应该有一个父级(PPID)产生 3 个子级(PIDS = 1,2,3)但我得到的是相同的 PID 和 PPID 3 次(我当前的代码)或在我得到 3 个父母之前,每个父母都有一个孩子,并且 PPIDS 和 PIDS 都不同,但 PPID 与以前的孩子 PID 相同。在我最近的尝试中,它永远不会在孩子(儿子)上方显示父母(爸爸)消息。它应该是这样的

[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

这是我的代码。如果可能的话,我只是在寻找提示,除非这只是我犯的一个愚蠢的错误,比如“哦,只需将 fork() 移动到子进程”或类似的东西。

我还有一个 child_count,以便我可以轻松地数孩子。

 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;
}

【问题讨论】:

  • 要记住两件事:第一是一旦你分叉,子进程会得到父进程内存的副本,当子进程修改时,例如variables 这些变量仅在孩子中更改,父母(或任何“兄弟姐妹”)不会看到这些变量更改。第二件事是您在else 案例中调用wait 将阻止父子。
  • 哦,您的代码中有一个不好的未定义行为。您定义了child 变量,然后在初始化它之前 使用它。未初始化的局部变量有一个 indeterminate 值,在没有初始化的情况下使用它们会导致 UB。你可能想考虑一下你在哪里打电话给fork
  • 哦,你的意思是像 pid_t child =0?你是什​​么意思 wait() 阻止父母和孩子?关于内存副本,您能给我一个示例代码吗?这样更容易看出这一点。
  • 关于wait,你在调用fork之后无条件地调用它,所以它会在父进程和子进程中被调用。如果您将child 初始化为零,代码将在您的条件下采用什么路径?并且进程不共享内存,进程中的内存仅用于该进程,并且该内存包含child_count之类的变量,因此在一个进程中修改变量不会导致在任何其他进程中对其进行修改。再次,想想你在哪里做或应该做fork电话
  • 最后的while循环需要是for(i=0;i&lt;3;i++)循环。如果你在while 循环的主体中放置一个printf,你会发现它永远不会运行,因为i 由于前面的for 循环已经是3。

标签: c linux unix process fork


【解决方案1】:

您必须记住的一件事是,当您fork 时,父子节点都将继续运行该点的代码。

因此,如果您没有正确地进行子/父检测,那么子很可能会启动他们的自己的子。

启动三个子代而没有孙代的一个好方法是将计数器与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 将确保只有父节点进行任何分叉,并且计数会将其限制为特定数量。


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

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

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

【讨论】:

    【解决方案2】:

    家长需要
    - 打印消息
    - 三次调用 fork
    - 等待三个孩子退出

    每个孩子都需要
    - 打印消息
    - 退出

    所以代码就这么简单

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-21
      • 1970-01-01
      • 1970-01-01
      • 2017-09-12
      • 2017-03-25
      • 2021-12-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多