简体   繁体   English

使用 fork() 的 C 程序的行为

[英]Behavior of a C program using fork()

Given the following code, I have to check its behavior, that is, how much processes are produced.给定以下代码,我必须检查它的行为,即产生了多少进程。

#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char*argv[])
{
    int pid, i , j;
    pid_t t;
    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
            if (t != 0) {
                t = fork();
                break;
            }
        }
        if (pid != getpid())
            break;
    }

    printf("I am the process %d and my father is the process %d\n", getpid(), getppid());

    while(wait(NULL)>0) {}

    return 0;
}

After compiling and executing, the output is as follows:编译执行后output如下:

I am the process 3749 and my father is the process 2254

I am the process 3750 and my father is the process 3749

I am the process 3751 and my father is the process 3749

I am the process 3752 and my father is the process 3749

I am the process 3754 and my father is the process 3749

I am the process 3753 and my father is the process 3750

I am the process 3755 and my father is the process 3750

I am the process 3756 and my father is the process 3752

I am the process 3757 and my father is the process 3752

I am the process 3758 and my father is the process 3756

I am the process 3759 and my father is the process 3756

This means the corresponding tree process looks like this:这意味着相应的树过程如下所示:

                      2254
                       |
                   -- 3749 ----
                  /   |   \    \
                3750 3751 3752 3754
               /   \      /  \
            3753  3755  3756 3757
                       /   \
                     3758  3759

In total, 11 processes are produced, if we count the initial process.如果我们计算初始进程,总共会产生 11 个进程。

I expected much more processes to be generated than just 11;我预计会生成更多的进程,而不仅仅是 11 个; anyway, I am able to understand the spawning of all processes but the most distant leaves (3758 and 3759).无论如何,我能够理解除了最远的叶子(3758 和 3759)之外的所有进程的产卵。

In the program there are two for loops, being one nested into the other.在程序中有两个 for 循环,一个嵌套在另一个中。 As two break statements are inside each loop, I guess that a loop or the two should finish at some point before their natural end.由于每个循环中有两个 break 语句,我猜一个或两个循环应该在其自然结束之前的某个时间点完成。

Could somebody confirm this code's behavior?有人可以确认此代码的行为吗?

Thank you in advance先感谢您

These kinds of programs are more to illustrate that you understand how forking works, I hope you never write a forking program within multiple nested loops complete with breaks.这些类型的程序更多是为了说明您了解分叉是如何工作的,我希望您永远不要在多个嵌套循环中编写分叉程序,其中包含中断。

They way you track this is by simulating the machine on paper, but each time you simulate the fork, you copy the simulation, setting the return code of fork() for one copy to zero, and the return code of the other copy to the other process's pid.他们跟踪这一点的方法是通过在纸上模拟机器,但是每次模拟分叉时,您都会复制模拟,将fork()的返回代码设置为一个副本为零,并将另一个副本的返回代码设置为其他进程的pid。

Let me reformat your program to make it easier让我重新格式化您的程序以使其更容易

    int pid;
    int i;
    int j;
    pid_t t;

will hold our "current values" for a process.将保存我们的“当前值”的过程。 We will also indicate the instruction pointer location with "IP ==>"我们还将用“IP ==>”指示指令指针位置

    int pid;
    int i;
    int j;
    pid_t t;
    IP ===>
    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
            if (t != 0) {
                t = fork();
                break;
            }
        }
        if (pid != getpid())
            break;
    }

Next step (for PID 1)下一步(对于 PID 1)

    === PROCESS 1 ====
    int pid;
    int i; (set to 0)
    int j;
    pid_t t;

    for (i = 0; i < 2; i++) {
    IP ===>
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
            if (t != 0) {
                t = fork();
                break;
            }
        }
        if (pid != getpid())
            break;
    }

next step (for PID 1)下一步(对于 PID 1)

    === PROCESS 1 ====
    int pid (set to 1  // fake pid, but easy to count)
    int i; (set to 0)
    int j;
    pid_t t;

    for (i = 0; i < 2; i++) {
        pid = getpid();
    IP ===>
        for (j = 0 ; j < i+2; j++){
            t = fork();
            if (t != 0) {
                t = fork();
                break;
            }
        }
        if (pid != getpid())
            break;
    }

next step (for process 1)下一步(用于流程 1)

    === PROCESS 1 ====
    int pid (set to 1)
    int i; (set to 0)
    int j; (set to 0)
    pid_t t;

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
    IP ===>
            t = fork();
            if (t != 0) {
                t = fork();
                break;
            }
        }
        if (pid != getpid())
            break;
    }

next step (for PID 1)下一步(对于 PID 1)

    === PROCESS 1 ====
    int pid (set to 1)
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 2, parent process)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
    IP ===>
            if (t != 0) {
                t = fork();
                break;
            }
        }
        if (pid != getpid())
            break;
    }
    === PROCESS 2 ===
    int pid (set to 1)
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 0, child process)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
    IP ===>
            if (t != 0) {
                t = fork();
                break;
            }
        }
        if (pid != getpid())
            break;
    }

next step (for PROCESS 1)下一步(对于过程 1)

    === PROCESS 1 ====
    int pid (set to 1)
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 2, parent process)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
            if (t != 0) {  // t == 2 in this process, so enter the block
   IP ===>
                t = fork();
                break;
            }
        }
        if (pid != getpid())
            break;
    }
    === PROCESS 2 ===
    int pid (set to 1)
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 0, child process)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
    IP ===>
            if (t != 0) {
                t = fork();
                break;
            }
        }
        if (pid != getpid())
            break;
    }

next step (for PID 1)下一步(对于 PID 1)

    === PROCESS 1 ====
    int pid (set to 1)
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 2, parent process)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
    IP ===>
            if (t != 0) {
                t = fork();
                break;
            }
        }
        if (pid != getpid())
            break;
    }
    === PROCESS 2 ===
    int pid (set to 1)
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 0, child process)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
    IP ===>
            if (t != 0) {
                t = fork();
                break;
            }
        }
        if (pid != getpid())
            break;
    }

next step (for PROCESS 1)下一步(对于过程 1)

    === PROCESS 1 ====
    int pid (set to 1)
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 2, parent process)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
            if (t != 0) {  
   IP ===>
                t = fork();
                break;
            }
        }
        if (pid != getpid())
            break;
    }
    === PROCESS 2 ===
    int pid (set to 1)
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 0, child process)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
    IP ===>
            if (t != 0) {
                t = fork();
                break;
            }
        }
        if (pid != getpid())
            break;
    }

next step (for PROCESS 1)下一步(对于过程 1)

    === PROCESS 1 ====
    int pid (set to 1)
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 3, parent process)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
            if (t != 0) {  
                t = fork();
   IP ===>
                break;
            }
        }
        if (pid != getpid())
            break;
    }
    === PROCESS 2 ===
    int pid (set to 1)
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 0, child process)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
    IP ===>
            if (t != 0) {
                t = fork();
                break;
            }
        }
        if (pid != getpid())
            break;
    }
    === PROCESS 3 ====
    int pid (set to 1)
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 0, child of PID 1)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
            if (t != 0) {  
                t = fork();
   IP ===>
                break;
            }
        }
        if (pid != getpid())
            break;
    }

next step (for PROCESS 1)下一步(对于过程 1)

    === PROCESS 1 ====
    int pid (set to 1)
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 3, parent process)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
            if (t != 0) {  
                t = fork();
                break;
            }
        }
    IP ===>
        if (pid != getpid())
            break;
    }
    === PROCESS 2 ===
    int pid (set to 1)
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 0, child process)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
    IP ===>
            if (t != 0) {
                t = fork();
                break;
            }
        }
        if (pid != getpid())
            break;
    }
    === PROCESS 3 ====
    int pid (set to 1)
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 0, child of PID 1)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
            if (t != 0) {  
                t = fork();
    IP ===>
                break;
            }
        }
        if (pid != getpid())
            break;
    }

next step (for PROCESS 1)下一步(对于过程 1)

    === PROCESS 1 ====
    int pid (set to 1)
    int pid = 1;
    int i; (set to 0)
    int j; (set to 1, due to j++)
    pid_t t; (set to 3, parent process)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
            if (t != 0) {  // t == 2 in this process, so enter the block
                t = fork();
                break;
            }
        }
        if (pid != getpid())  // pid == 1, getpid == 1. so skip break
            break;
    IP ===>
    }
    === PROCESS 2 ===
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 0, child process)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
    IP ===>
            if (t != 0) {
                t = fork();
                break;
            }
        }
        if (pid != getpid())
            break;
    }
    === PROCESS 3 ====
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 0, child of PID 1)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
            if (t != 0) {  // t == 2 in this process, so enter the block
                t = fork();
    IP ===>
                break;
            }
        }
        if (pid != getpid())
            break;
    }

next step (for PROCESS 1)下一步(对于过程 1)

    === PROCESS 1 ====
    int pid (set to 1)
    int pid = 1;
    int i; (set to 1)
    int j; (set to 1, due to j++)
    pid_t t; (set to 3, parent process)

    for (i = 0; i < 2; IP ===> i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
            if (t != 0) {  // t == 2 in this process, so enter the block
                t = fork();
                break;
            }
        }
        if (pid != getpid())  // pid == 1, getpid == 1. so skip break
            break;

    }
    === PROCESS 2 ===
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 0, child process)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
    IP ===>
            if (t != 0) {
                t = fork();
                break;
            }
        }
        if (pid != getpid())
            break;
    }
    === PROCESS 3 ====
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 0, child of PID 1)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
            if (t != 0) {  // t == 2 in this process, so enter the block
                t = fork();
    IP ===>
                break;
            }
        }
        if (pid != getpid())
            break;
    }

next step (for PROCESS 1)下一步(对于过程 1)

    === PROCESS 1 ====
    int pid (set to 1)
    int pid = 1;
    int i; (set to 1)
    int j; (set to 1, due to j++)
    pid_t t; (set to 3, parent process)

    for (i = 0; IP ===> i < 2;  i++) { // 1 is less than 2 so enter loop block
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
            if (t != 0) {  // t == 2 in this process, so enter the block
                t = fork();
                break;
            }
        }
        if (pid != getpid())  // pid == 1, getpid == 1. so skip break
            break;

    }
    === PROCESS 2 ===
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 0, child process)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
    IP ===>
            if (t != 0) {
                t = fork();
                break;
            }
        }
        if (pid != getpid())
            break;
    }
    === PROCESS 3 ====
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 0, child of PID 1)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
            if (t != 0) {  // t == 2 in this process, so enter the block
                t = fork();
    IP ===>
                break;
            }
        }
        if (pid != getpid())
            break;
    }

next step (for PROCESS 1)下一步(对于过程 1)

    === PROCESS 1 ====
    int pid (set to 1)
    int pid = 1;
    int i; (set to 1)
    int j; (set to 1)
    pid_t t; (set to 3, parent process)

    for (i = 0; i < 2;  i++) {
    IP ===>
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
            if (t != 0) {  // t == 2 in this process, so enter the block
                t = fork();
                break;
            }
        }
        if (pid != getpid())  // pid == 1, getpid == 1. so skip break
            break;

    }
    === PROCESS 2 ===
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 0, child process)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
    IP ===>
            if (t != 0) {
                t = fork();
                break;
            }
        }
        if (pid != getpid())
            break;
    }
    === PROCESS 3 ====
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 0, child of PID 1)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
            if (t != 0) {  // t == 2 in this process, so enter the block
                t = fork();
    IP ===>
                break;
            }
        }
        if (pid != getpid())
            break;
    }

next step (for PROCESS 1)下一步(对于过程 1)

    === PROCESS 1 ====
    int pid (set to 1, again)
    int pid = 1;
    int i; (set to 1)
    int j; (set to 1)
    pid_t t; (set to 3)

    for (i = 0; i < 2;  i++) {
        pid = getpid();
    IP ===>
        for (j = 0 ; j < i+2; j++){
            t = fork();
            if (t != 0) {  // t == 2 in this process, so enter the block
                t = fork();
                break;
            }
        }
        if (pid != getpid())  // pid == 1, getpid == 1. so skip break
            break;

    }
    === PROCESS 2 ===
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 0, child process)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
    IP ===>
            if (t != 0) {
                t = fork();
                break;
            }
        }
        if (pid != getpid())
            break;
    }
    === PROCESS 3 ====
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 0, child of PID 1)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
            if (t != 0) {  // t == 2 in this process, so enter the block
                t = fork();
    IP ===>
                break;
            }
        }
        if (pid != getpid())
            break;
    }

next step (for PROCESS 1)下一步(对于过程 1)

    === PROCESS 1 ====
    int pid (set to 1)
    int pid = 1;
    int i; (set to 1)
    int j; (set to 0)
    pid_t t; (set to 3)

    for (i = 0; i < 2;  i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
    IP ===>
            t = fork();
            if (t != 0) {  // t == 2 in this process, so enter the block
                t = fork();
                break;
            }
        }
        if (pid != getpid())  // pid == 1, getpid == 1. so skip break
            break;

    }
    === PROCESS 2 ===
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 0, child process)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
    IP ===>
            if (t != 0) {
                t = fork();
                break;
            }
        }
        if (pid != getpid())
            break;
    }
    === PROCESS 3 ====
    int i; (set to 0)
    int j; (set to 0)
    pid_t t; (set to 0, child of PID 1)

    for (i = 0; i < 2; i++) {
        pid = getpid();
        for (j = 0 ; j < i+2; j++){
            t = fork();
            if (t != 0) {  // t == 2 in this process, so enter the block
                t = fork();
    IP ===>
                break;
            }
        }
        if (pid != getpid())
            break;
    }

And so on.等等。 Once you get Process 1 out of it's loops (and waiting for its children complete), you follow the same procedure for Process 2 until it is out of it's loops and waiting for it's children to complete.一旦你让进程 1 退出它的循环(并等待它的子进程完成),你对进程 2 遵循相同的过程,直到它离开它的循环并等待它的子进程完成。

The point of this exercise is if you can simulate some confusing process code.本练习的重点是您是否可以模拟一些令人困惑的流程代码。 It is clear that since the top level process will loop twice, and it never breaks out of the loop, you will get 4 processes under it.很明显,由于顶级进程将循环两次,并且它永远不会跳出循环,因此您将在其下获得 4 个进程。 As you practice stepping through the other processes, you will start to see the patterns they implement.当您练习逐步完成其他流程时,您将开始看到它们实现的模式。

Personally, this kind of problem is a lot of work, and not the kind of work that makes you a better programmer;就个人而言,这类问题需要大量的工作,而不是让你成为更好的程序员的工作; but, it will demonstrate if you understand that a program is forked with it's current state (notice that pid is wrong in many of the children, because it wasn't updated after the fork), and if you understand that fully, you can simulate the program to it's final completion.但是,它会证明你是否理解一个程序是用它当前的 state 分叉的(请注意,许多孩子的 pid 是错误的,因为它在分叉后没有更新),如果你完全理解,你可以模拟该程序最终完成。

Of course, we use computers to automate boring stuff (like this), so you might want to come up with a new logging line like this:当然,我们使用计算机来自动化无聊的事情(像这样),所以你可能想想出一个像这样的新日志行:

 void printState(int me, int pid, int i, int j, int t) {
     printf("PID %d: pid = %d, i = %d, j = %d, t = %d\n");
 }

and then run然后运行

   printState(getpid(), pid, i, j, t);
   for (i = 0; i < 2; i++) {
        printState(getpid(), pid, i, j, t);
        pid = getpid();
        printState(getpid(), pid, i, j, t);
        for (j = 0 ; j < i+2; j++){
            printState(getpid(), pid, i, j, t);
            t = fork();
            printState(getpid(), pid, i, j, t);
            if (t != 0) {
                printState(getpid(), pid, i, j, t);
                t = fork();
                printState(getpid(), pid, i, j, t);
                break;
            }
        }
        if (pid != getpid())
            printState(getpid(), pid, i, j, t);
            break;
    }

and collect the output, ordering them by their self-reported pid numbers (getpid(), not pid variable)并收集 output,按照他们自己报告的 pid 编号(getpid(),而不是 pid 变量)对它们进行排序

Based the program's simulation explained by @Edwin Buck (thank you Edwin,): here's the process creation procedure:基于@Edwin Buck 解释的程序模拟(谢谢 Edwin,):这是流程创建过程:

                    1
                    |
               ---- 2 -----
              /   /   \    \
             3   4     5    6
           /   \      /  \
          7     8    9   10
                   /   \
                  11   12

Process #1: Initial process's father.进程#1:初始进程的父亲。

Process #2: Initial process.过程#2:初始过程。 It's the only process which fulfills pid = getpid().它是唯一满足 pid = getpid() 的进程。

Process #3: Spawned at i = 0, j = 0.过程 #3:在 i = 0、j = 0 时生成。

Process #4: Spawned at i = 0, j = 0.过程#4:在 i = 0,j = 0 时产生。

Process #7: Spawned at i = 0, j = 1.过程 #7:在 i = 0、j = 1 时生成。

Process #8: Spawned at i = 0, j = 1.过程 #8:在 i = 0、j = 1 时生成。

Process #5: Spawned at i = 1, j = 0.过程 #5:在 i = 1、j = 0 时生成。

Process #6: Spawned at i = 1, j = 0.进程 #6:在 i = 1、j = 0 时生成。

Process #9: Spawned at i = 1, j = 1.过程 #9:在 i = 1、j = 1 处生成。

Process #10: Spawned at i = 1, j = 1.过程 #10:在 i = 1、j = 1 处生成。

Process #11: Spawned at i = 1, j = 2.过程 #11:在 i = 1、j = 2 处生成。

Process #12: Spawned at i = 1, j = 2.过程 #12:在 i = 1、j = 2 处生成。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM