【问题标题】:Processes not executing in expected order; fork() and waitpid()进程未按预期顺序执行; fork() 和 waitpid()
【发布时间】:2022-01-17 07:04:29
【问题描述】:

我写了一个程序,两次调用fork(),生成三个孩子和一个父母。

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

int main() {
    int child1 = fork();
    int child2 = fork();

    // Check for error
    if (child1 < 0 || child2 < 0) {
        fprintf(stderr, "A fork failed :(\n");
        exit(1);
    }

    // Parent Process
    if (child1 > 0 && child2 > 0) {
        waitpid(child1, NULL, 0);
        waitpid(child2, NULL, 0);
        printf("I'm the parent\n");
    }
    // Child B -- CONFUSION AREA --
    else if (child1 > 0 && child2 == 0) {
        waitpid(child1, NULL, 0); // Not waiting for process to finish
        printf("I'm child B\n");
    }
    // Child A
    else if (child1 == 0 && child2 > 0) {
        waitpid(child2, NULL, 0);
        printf("I'm child A\n");
    }
    // Child C
    else if (child1 == 0 && child2 == 0) {            
        printf("I'm child C\n");
    }

    return 0;
}

我正在尝试打印出来

I'm child C
I'm child A
I'm child B
I'm the parent

但是程序会打印出来

I'm child B
I'm child C
I'm child A
I'm the parent

我很困惑为什么孩子 B 不等待 child1process 完成?

我画了一个流程树来尝试了解发生了什么,我的理解是它看起来像:

/*

         Parent (15543)
         child1 = 15544;
         child2 = 15545
           /       \
          /         \
         /           \
        A (15544)     B (15545)
     child1 = 0;      child1 = 15544;
     child2 = 15546;  child2 = 0;
        /
       /
      /
     C (15546)
     child1 = 0;
     child2 = 0;


*/

【问题讨论】:

标签: c operating-system


【解决方案1】:

当子 B 调用 waitpid() 时,调用失败并返回 -1,因为父进程已经在等待子 A,并且您不能两次获取子进程。

对于您想要的行为,您最好使用进程间信号量来同步您的进程执行。尝试包含semaphore.h 并查看sem_init() 的文档。

【讨论】:

  • 子 B 出错但不是因为你说的原因,子 B 出错是因为它没有启动任何子。它有child1 &gt; 0,因为当它已经从第一个fork() 调用初始化时,它从父进程继承了变量值......但它不是该进程的父进程,所以它不能wait() 它。孩子连接到他们的父母,但不连接到其他进程,wait() 只适用于实际的孩子。
【解决方案2】:

当您执行第一个fork() 时,两个进程(父进程和子进程)都会转到第二个fork() 并生成您在树中看到的另外两个进程。这就是您在输出中看到孙子的原因。你认为只执行了两个 fork,所以期望有两个子进程,但你没有意识到第二个 fork() 实际上是由两个进程执行的:父 和第一个 fork() 调用的子进程强>。

顺便说一句,内核以任意顺序调度进程,因此您可以在输出行中期望不同的顺序。孩子 B 不能 waitpid() 因为它还没有启动任何孩子(它是你树中的孩子 B,它有父母为孩子 A 获得的 pid,但孩子 A 不是它的孩子,所以 waitpid() 给你一个错误,您没有检查,因此打印完成)您假设它是父变量,因为其中一个子变量> 0,但他继承了从其父变量初始化的变量,因为它没有执行 @ 987654327@电话。

【讨论】:

    猜你喜欢
    • 2020-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-15
    • 1970-01-01
    • 2012-08-29
    • 2015-07-26
    • 2019-02-22
    相关资源
    最近更新 更多