首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何让这个fork()函数打印一次,而不是在for循环中多次打印?

如何让这个fork()函数打印一次,而不是在for循环中多次打印?
EN

Stack Overflow用户
提问于 2021-10-05 19:44:35
回答 2查看 470关注 0票数 0

这是我第一次用C编写代码并使用分叉,所以我对它有点困惑。我的任务是创建10个总进程=1个父进程、3个子进程和6个子进程。这是我目前正在努力解决的孙辈过程。

代码语言:javascript
复制
int i=0, j=0, child_count=1, grand_count=1;

    for (i = 0; i < 3; i++) {
        pid_t child = 0;
        child = fork();
        
        if (child != 0) {            
            for (j = 0; j < 2; j++) {
                pid_t grand = 0;
                grand = fork();

                if (grand == 0){
                    printf("7I am grand #%d with PID %d and PPID %d\n", grand_count, getpid(), getppid());
                    exit(0);
                }
                grand_count++;
            }
        }
}

我需要它打印:

我是大人物#6,PID 4373和PPID 745

我是大人物,PID 4372和PPID 745

我是大人物#4,PID 4370和PPID 745

我是大人物#3,PID 4369和PPID 745

我是大人物2,PID 4367和PPID 745

我是大人物,PID 4366和PPID 745

但是相反,我得到了:

我是大人物,PID 4372和PPID 745

我是大人物#4,PID 4370和PPID 745

我是大人物#6,PID 4373和PPID 745

我是大人物#3,PID 4369和PPID 745

我是大人物2,PID 4367和PPID 745

我是大人物,PID 4366和PPID 745

我是大人物#4,PID 4376和PPID 745

我是大人物#3,PID 4375和PPID 745

我是大人物#4,PID 4382和PPID 745

我是大人物#3,PID 4381和PPID 745

我是大人物2,PID 4379和PPID 745

我是大人物,PID 4378和PPID 745

我是大人物2,PID 4385和PPID 745

我是大人物,PID 4384和PPID 745

它按顺序打印(我假设是因为for循环,但我不知道如何修复它,所以欢迎您提供任何建议)。但我也不知道如何防止它多次打印相同的行。

EN

回答 2

Stack Overflow用户

发布于 2021-10-05 20:15:01

  • 您的条件if (child != 0)是错误的,它后面的语句将由父进程执行。应该是if (child == 0)
  • You,永远不要退出子进程,这使得它们也循环并创建子进程。你应该先让大孩子们死掉,然后再把孩子们也处理掉。最后,terminate.
  • Counting
  • ,等着孩子们,你才会让这个程序像你做的那样工作。进程之间不共享grand_count变量。它是从每个fork.

上的当前父进程复制的。

示例:

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

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

        if(child == 0) {
            for(int j = 0; j < 2; j++) {
                pid_t grand = fork();

                if(grand == 0) {
                    printf("I am grand child with PID %d and PPID %d\n",
                           getpid(), getppid());
                    exit(0);
                }
            }

            // collect grand children
            for(pid_t who_died; (who_died = wait(NULL)) != -1;) {
                printf("grand child %d died\n", who_died);
            }
            exit(0); // and exit child
        }
    }

    // collect children
    for(pid_t who_died; (who_died = wait(NULL)) != -1;) {
        printf("child %d died\n", who_died);
    }
}

可能的产出:

代码语言:javascript
复制
I am grand child with PID 2120874 and PPID 2120872
I am grand child with PID 2120876 and PPID 2120873
I am grand child with PID 2120877 and PPID 2120872
I am grand child with PID 2120878 and PPID 2120875
I am grand child with PID 2120880 and PPID 2120873
I am grand child with PID 2120883 and PPID 2120875
grand child 2120874 died
grand child 2120877 died
grand child 2120880 died
grand child 2120876 died
grand child 2120878 died
grand child 2120883 died
child 2120873 died
child 2120875 died
child 2120872 died
票数 1
EN

Stack Overflow用户

发布于 2021-10-05 20:33:11

有几件事不对劲。

  • fork返回子进程的0。if (child != 0) {在父程序中运行(或一个错误)。
  • 每个叉都得到自己的所有变量的副本。每个子进程都在递增自己的grand_count.
  • You're,而不是等到子进程完成。

fork可能会非常令人困惑。在习惯它的同时,我鼓励使用基本的脚手架。

代码语言:javascript
复制
pid_t cpid = fork();
if (cpid == 0) {
    child_function();

    exit(0);
}
else if( cpid == -1 ) {
    fork_error_handler();
}

// parent code

通过将子代码放入一个空函数中,我们避免了嵌套循环和分叉。筑巢会使事情变得复杂。

考虑到这一点,我们可以重做您的外部循环,只执行派生子进程,并传递ID开始打印。

代码语言:javascript
复制
void fork_error_handler() {
    perror("fork() failed");
}

void wait_all() {
    // wait(NULL) waits for any child process to exit.
    // If there are no more child processes, it returns -1.
    // So to wait for all children to exit, keep calling wait
    // until it returns -1.
    while( wait(NULL) != -1 );
}

int main() {
    int num_children = 2;

    // From 0 to 2...
    for (int i = 0; i <= num_children; i++) {
        pid_t cpid = fork();

        if (cpid == 0) {
            // 1, 3, 5
            spawn_printers(i * num_children + 1);

            exit(0);
        }
        else if( cpid == -1 ) {
            fork_error_handler();
        }
    }

    wait_all();

}

生成所有的子程序,但是将它们的代码放入一个函数中。这避免了嵌套叉和嵌套循环。

我们还确保等待直到我们的所有子进程完成。如果没有此操作,父程序将在子程序之前处理我的退出。这可能会导致孩子在父母离开时被杀死。

现在我们可以编写一个单独的函数来生成打印过程。

代码语言:javascript
复制
void spawn_printers(int starting_id) {
    for (int i = 0; i < 2; i++) {
        int id = starting_id + i;

        pid_t cpid = fork();

        if (cpid == 0) {
            printf("I am grand #%d with PID %d and PPID %d\n", id, getpid(), getppid());
            exit(0);
        }
        else if( cpid == -1 ) {
            fork_error_handler();
        }
    }

    // Each child has to wait for its own children.
    wait_all();
}

这些东西会打印出不正常的。这就是叉子的本质。如果你需要它按照特定的顺序打印,问另一个问题。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69456417

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档