Detailed explanation of Linux system call fork() function

In Linux systems, fork() is a very important system call. Its function is to create a new process. Specifically, the fork() function will copy a child process in the address space of the current process, and this child process is almost identical to the parent process, including process code, data, stack, and open file descriptors. Therefore, the relationship between the parent process and the child process can be regarded as a "clone" relationship.

The syntax of the fork() function is as follows:

#include <unistd.h>  
pid_t fork(void);

Among them, the parameter pid_t represents the process id, and the return value of the fork() function has the following two situations:

  • If 0 is returned, it means that the current process is a child process.
  • If a positive integer is returned, it means that the current process is the parent process, and the returned integer is the process ID of the newly created child process.

In addition, if the return value of fork() is -1, it means that the creation of the child process failed.

The essence of the fork() function is to create a new process control block (PCB) in the kernel, then copy most of the contents of the original process's PCB to the new PCB, and then let the two processes run at the same time. Since the new process is copied from the original process, the new process will inherit all the resources and information of the original process, including memory, file descriptors, signal processing methods, etc.

It should be noted that the fork() function does not guarantee the execution order of the parent process and the child process. After fork(), the operating system may execute the parent process first or the child process first, which completely depends on the system's scheduling algorithm.

Under normal circumstances, the parent process and the child process are independent of each other. They each run their own code and share only a part of the memory space, while other resources are used separately.

#include<unistd.h>
#include<stdio.h>
int i=5;
int main() {
    if(fork()!=0)
        i++;
    else
        printf("%d\n",i);
}

In addition, the fork() function can also distinguish the parent process and the child process through the return value, which allows the parent process to manage the behavior of the child process, such as waiting for the child process to end, obtaining the status of the child process, etc.

#include <stdio.h>
#include<unistd.h>
int main() {
    for(int i=0;i<3;i++){
        printf("%d\n",fork());
    }
}

It should be noted that the fork function will return twice, once in the parent process to return the process ID of the child process, and once in the child process to return 0.

The following are seven fork examples

① Call once, return twice

void fork0() {
    if (fork() == 0) {
        printf("Hello from child\n");
    } else {
        printf("Hello from parent\n");
    }
}

Create a child process to print hello from child, and the parent process prints hello from parent

② Parent and child both run same code

void fork1() {
    int x = 1;
    pid_t pid = fork();

    if (pid == 0) {
        printf("Child has x = %d\n", ++x);
    } else {
        printf("Parent has x = %d\n", --x);
    }
    printf("Bye from process %d with x = %d\n", getpid(), x);
}

The child process will output child has x=2 and bye from process child process ID with x=2, and the parent process will output parent has x=0 and bye from process parent process ID with x=0

③ Parent and child can continue forking

void fork2() {
    printf("L0\n");
    fork();
    printf("L1\n");
    fork();
    printf("Bye\n");
}

The parent process outputs one L0, one L1 and one Bye, one child process outputs one L1 and one Bye, one child process outputs one Bye, and two grandson processes output two Bye, a total of one L0, two L1 and four Bye.

④ Parent and child can continue forking

#define bork fork

void borkfork() {
    bork();
    bork();
    bork();
    printf("borked\n");
}

The parent process creates a child process, and then the two create two more child processes, and then the four create four more child processes, a total of eight processes output eight borkforks.

⑤ Parent and child can continue forking

void fork3() {
    printf("L0\n");
    fork();
    printf("L1\n");
    fork();
    printf("L2\n");
    fork();
    printf("Bye\n");
}

It can be seen from ③ and ④ that one L0, two L1, four L2 and eight Bye will be output.

⑥ Nested forks in parents

void fork4() {
    printf("L0\n");
    if (fork() != 0) {
        printf("L1\n");
        if (fork() != 0) {
            printf("L2\n");
            fork();
        }
    }
    printf("Bye\n");
}

Since only the return value of fork in the parent process will be the process ID, and the return value of fork in the child process is always 0, so only the parent process will print out L0, L1 and L2 and create three child processes. The four processes will then Print out four Bye

⑦ Nested forks in children

void fork5() {
    printf("L0\n");
    if (fork() == 0) {
        printf("L1\n");
        if (fork() == 0) {
            printf("L2\n");
            fork();
        }
    }
    printf("Bye\n");
}

The parent process prints out L0, the child process prints out L1, the child process created by the child process prints out L2 and creates a child process, and the four processes print four Bye

Guess you like

Origin blog.csdn.net/weixin_62264287/article/details/133529869