关于在Unix系统上fork进程中进程ID的两个问题,需要帮助 - C语言

3

编辑:我的大脑显然自动将pid[1]更正为pid[0]。第一个问题的答案是因为我瞎了。

我们的大学提供了以下代码示例,我添加了一个打印调用以更好地理解实际发生的情况,并使用所有实际返回值。

我原以为我理解了如何分叉和分配进程ID,但实际上并不是这样。

我不明白其中两件事:

  1. 为什么主进程的进程ID(getpid())等于主进程内部fork()的返回值?它说fork返回子进程的pid。而getpid()返回调用进程的pid,按照逻辑来说它们不能相等。
  2. 为什么在最后一个例程中pid0和pid2都是零,或者确切地说,最后一个fork()调用中调用了哪个呢?我假设其中一个被克隆了,而另一个代表最后一个fork()的返回值。

我是Stackoverflow的新手,非常感谢您的帮助!

int v[3] = {0, 0, 0};

void handler(int sig) {
    v[0]++;
}


 int main() {

    int pid[3];

    signal(SIGUSR1, handler);
    printf("Main Process ID: %d\n", getpid());

    pid[0] = fork();
    pid[1] = getpid();
    pid[2] = fork();

    if (pid[0] == pid[2]) {
        v[1]++;
        sleep(4);
    } else if (pid[1] == getppid()) {
        sleep(3);
        v[2]++;
        sleep(2);
    } else if (pid[1] == getpid()) {
        sleep(1);
        v[2]++;
        kill(pid[2], SIGUSR1);
        wait(NULL);
        if (pid[0] > 0) {
            v[1]++;
            wait(NULL);
        }
    }

    printf("ppid %d, processID %d, pid0 %d, pid1 %d, pid2 %d\n", getppid(), getpid(), pid[0], pid[1], pid[2]);
    printf("%d %d %d\n", v[0], v[1], v[2]);
}

Result:
Main Process ID: 286161
// 2. Fork (I assume)
ppid 286162, processID 286164, pid0 0, pid1 286162, pid2 0
1 1 0
// 2. Fork (I assume)
ppid 286161, processID 286162, pid0 0, pid1 286162, pid2 286164
0 0 1
// 1. Fork (I assume)
ppid 286161, processID 286163, pid0 286162, pid1 286161, pid2 0
1 0 1
// Main Process
ppid 154332, processID 286161, pid0 286162, pid1 286161, pid2 286163
0 1 1

2
请查看 man 2 wait 底部的示例,了解如何确定父进程和子进程将执行哪些代码。当发生 fork() 时,您正在处理两个独立的进程。如果不防范父进程和子进程将要执行的代码,则子进程将执行在其之后的所有命令(包括第二次调用 fork() 在父进程和第一个子进程中都会被执行)。 - David C. Rankin
谢谢!@DavidC.Rankin 这就是我猜它会工作的方式。感谢您的确认。 我第一个问题只是因为我眼瞎了。 - LoweloDev
1个回答

5

Fork系统调用返回值0代表子进程,返回子进程的PID代表父进程。

首先,让我们来看一下这个:

    pid[0] = fork(); // <-- forks child_1. Returns PID(child_1) in parent, 0 in child_1
    pid[1] = getpid(); // <-- Returns PID(parent) in parent, PID(child_1) in child_1
    pid[2] = fork(); // <-- Forks child_2 from parent, forks child_3 from child_1. Returns PID(child_2) in parent, 0 in child_2, PID(child_3) in child_1, 0 in child_3

第一个fork调用会生成一个子进程,它是从父进程复制而来的。第二次调用fork时,由于程序已经被复制了一份,因此会生成两个进程:其中一个是原始父进程的兄弟(即child_1),另一个是第一个子进程的子孙(即原始父进程的孙子)。

因此,在这种情况下:

1) ppid 286162, processID 286164, pid0 0, pid1 286162, pid2 0
2) ppid 286161, processID 286162, pid0 0, pid1 286162, pid2 286164
3) ppid 286161, processID 286163, pid0 286162, pid1 286161, pid2 0
4) ppid 154332, processID 286161, pid0 286162, pid1 286161, pid2 286163

我会给每行命名:(1)是child_3,(2)是child_1,(3)是child_2,(4)是parent。
如果您把它画出来并逐行分步执行,会更容易理解。
从这里开始:
            SHELL
              |
            Parent

然后调用fork

            SHELL
              |
            Parent
            /
      child_1

在父进程中:PID[0] = 子进程1的pid
在子进程1中:PID[0] = 0

接下来,调用getpid函数。

在父进程中:PID[1] = 父进程的pid
在子进程1中:PID[1] = 子进程1的pid

然后进行第二次fork调用:

            SHELL
              |
            Parent
            /    \
      child_1    child_2
         |
      child_3

在父进程中:PID [2] = 子进程_2的进程ID
在子进程_1中:PID [2] = 子进程_3的进程ID
在子进程_2中:PID [0]PID [1] 继承自父进程,因此 PID [0]=子进程_1的进程IDPID [1] = 父进程的进程ID,并且 PID [2] = 0
在子进程_3中:PID [0]PID [1] 继承自子进程_1,因此 PID [0] = 0PID [1] = 子进程_1的进程ID,并且 PID [2] = 0


我在这里发布的代码中可能犯了错误,或者我对比较pid[1]而不是pid[0]与getpid()的事实视而不见。如果是这样,请原谅我。我的ADHD开始作祟了。稍后会在另一个操作系统中查看它。 - LoweloDev
非常感谢!第一个问题只是我的大脑拒绝看到正确的数字pid[1],而不是与getpid()相比的pid[0],而你解释了第二个问题,正如我猜测它是如何工作的一样! - LoweloDev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接