How do 2 or more fork system calls work?

2019-01-20 19:27发布

Here's a code where I use 2 fork() system calls one after another - How does it actually work?

 #include <unistd.h>
 #include <iostream.h>
 using namespace std;

 int main()
 {
    cout << "0. I am process " << getpid() << endl;
    (void) fork();
    cout << "1. I am process " << getpid() << endl;
    (void) fork();
    cout << "2. I am process " << getpid() << endl;
}

I get the output as :
0. I am process 27701
1. I am process 25915
1. I am process 27701
2. I am process 27781
2. I am process 26170
2. I am process 27701

This is the next program where I've used 3 fork system calls, how do I get such an output? If I were to solve this code manually, what would be the logic?

#include <unistd.h>
#include <iostream>
using namespace std;

int main()
{
    cout << "0. I am process " << getpid() << endl;
    (void) fork();
    cout << "1. I am process " << getpid() << endl;
    (void) fork();
    cout << "2. I am process " << getpid() << endl;
    (void) fork();
    cout << "3. I am process " << getpid() << endl;
}

Here I get the output as :
0. I am process 27116
1. I am process 26147
2. I am process 27371
2. I am process 26147
3. I am process 24416
3. I am process 27371
3. I am process 27508
3. I am process 26147
1. I am process 27116
2. I am process 21406
2. I am process 27116
3. I am process 27369
3. I am process 21406
3. I am process 26752
3. I am process 27116

4条回答
何必那么认真
2楼-- · 2019-01-20 20:19

when a fork() is called, a child process is created and ran. So you are getting the following statement executed once in the child process:

cout << "1. I am process " << getpid() << endl;

Further, when another fork is called, another child process is created which runs the next 'cout' statement. However, the parent process is also ran. This happens for the third fork() also.

All this takes place in the child process of the first fork(). After this the parent process for the 1st fork runs as well to show your output.

查看更多
甜甜的少女心
3楼-- · 2019-01-20 20:21

fork() works the same way every time you call it. A new process is created as an exact copy of the current process, and both continue execution as if they both just returned from the fork() function call, just with different return values. In your case you throw away that return value, so they're just identical processes.

Let's draw a picture for your first example. Sample output from a run I just made (since the output you put in your question is incomplete):

0. I am process 25597
1. I am process 25597
2. I am process 25597
1. I am process 25598
2. I am process 25599
2. I am process 25598
2. I am process 25600

You start with a single process with PID 25597. It prints the 0 line, and then forks. That yields two processes:

            25597          # prints "0"
             /\
            /  \
           /    \
         25597 25598       # both print "1"

So far so good. Now both of these new processes call fork() again. The complete tree ends up looking like this:

                   25597
                    /\
                   /  \
                  /    \
                 /      \
                /        \
             25597      25598       # both print "1"
              /\          /\
             /  \        /  \
            /    \      /    \
         25597  25599 25598 25600   # all four print "2"

The actual locations of 25599 and 25600 can't be guessed from the output, unfortunately - they could be the other way around, too.

For your 3-fork() example, you just have to do the same thing, but it will have another level in the diagram - you'll end up with 8 processes each printing the "3" line.

查看更多
闹够了就滚
4楼-- · 2019-01-20 20:25

Just draw a tree where each root node is a fork call and leaf nodes are the code following it.

In the first program, your cout<<"0..." is the parent program and after the fork call, the whole program after that line executes twice.Hence the two "1..." output lines.

Now there is another fork call after this. This time there are 3 processes running( 1.The original parent you invoked, 2. The child it spawned 3. The child itself spawns another grandchild.)
Hence the 3 "2..." output lines.

查看更多
兄弟一词,经得起流年.
5楼-- · 2019-01-20 20:32

Your program is utterly wrong. You should never ignore the result of fork.

Read the Advanced Linux programming book and the fork(2) man page (read that page several times and carefully).

Typical code should be:

  pid_t pid1 = fork();
  if (pid1<0) { perror("fork1 failed"); exit(EXIT_FAILURE); }
  else if (pid1 == 0) {
     // you are in the child process
  }
  else // pid1>0 
  {  // you are in the parent process
  }

And likewise for pid_t pid2=fork(); and then for pid_t pid3=fork(); etc.... So each call to fork should handle the 3 cases of result of fork (failure i.e. <0, child process ==0, parent process >0)

In principle you have 33 i.e. 27 possibilities. But you could handle early the failure case, which leaves 23 i.e. 8. possibilities

Don't forget to handle the failure of fork. You might lower your process limit (with setrlimit(2) using RLIMIT_NPROC or the equivalent ulimit bash builtin) to ease the test of fork failure.

查看更多
登录 后发表回答