Linux: process replication (fork)

Keywords: C Linux server

Copy process fork method

Basic concepts

First, let's look at the fork method: create a child process. The process calling fork function is the parent process, and the newly generated process is the child process.

The format is:

pid_t fork(void);

Return the pid of the child process in the parent process, 0 in the child process, and - 1 in case of failure.
Illustration:

Create child process example

Example 1:

#include<stdio.h>
#include<unistd.h>
#include<assert.h>
#include<stdlib.h>

int main(void)
{
    char* s = NULL;
    int n = 0;

    pid_t pid = fork();
    assert(pid != -1);

    if (pid == 0)
    {
        s = "child";
        n = 3;
    }
    else
    {
        s = "parent";
        n = 7;
    }

    for (int i = 0; i < n; ++i)
    {
        printf("%s\n", s);
        sleep(1);
    }

    exit(0);
}

Operation results:

Run result description: the copied child process is equivalent to copying the parent process code, and runs concurrently with the parent process. Each run result may be different.

For example, the second print result is different from the above.

getpid() and getppid()

According to the help manual:
getpid() is the ID that returns the process.

Example:

For the above example, change the output in the for loop to see what getpid() does

 	for (int i = 0; i < n; ++i)
    {
        printf("s = %s, pid = %d\n", s, getpid());
        sleep(3);
    }

Running example:

getppid() returns the ID of the parent process of the current process...

Example:

	for (int i = 0; i < n; ++i)
    {
        printf("s = %s, pid = %d, ppid = %d\n", s, getpid(), getppid());
        sleep(3);
    }

Running example:

It can be seen that the pid of the child process is the ID of the parent process

fork exercise

Example:
How many A's will the following code output?

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>

int main(void)
{
    int i = 0;

    for (; i < 2; ++i)
    {
        fork();
        printf("A\n");
    }

    exit(0);
}

Running example:

analysis:
Because a copy of the current program will be copied every time the loop comes in, it will be copied all the time if the for loop conditions are met

Dead process and treatment method

Concept: the child process ends before the parent process. The parent process does not call wait to obtain the child process exit code.

Dead process example

code:
Write a program that allows the child process to end first

#include<stdio.h>
#include<assert.h>
#include<unistd.h>
#include<stdlib.h>

int main(void)
{
    char* s = NULL;
    int n = 0;

    pid_t pid = fork();
    assert(pid != -1);

    if (pid == 0)
    {
        s = "child";
        n = 3;
    }
    else
    {
        s = "parent";
        n = 6;
    }

    int i = 0; 

    for (i; i < n; ++i)
    {
        printf("s = %s, pid = %d\n", s, getpid());
        
        sleep(3);
    }

    exit(0);
}

Operation results:

The system calls the process in this state a dead process < defunct >.

Dead process processing method

The parent process uses the wait() method

Introduction:

NAME
       wait, waitpid, waitid - wait for process to change state

SYNOPSIS
       #include <sys/types.h>
       #include <sys/wait.h>

       pid_t wait(int *wstatus);

 	   WIFEXITED(wstatus)
              returns true if the child terminated normally, that is, by call‐
              ing exit(3) or _exit(2), or by returning from main().

       WEXITSTATUS(wstatus)
              returns  the  exit  status  of  the child.  This consists of the
              least significant 8 bits of the status argument that  the  child
              specified  in  a  call to exit(3) or _exit(2) or as the argument
              for a return statement in main().  This macro should be employed
              only if WIFEXITED returned true.

       WIFSIGNALED(wstatus)
              returns true if the child process was terminated by a signal.

When the parent process calls wait(), it will immediately block itself. Wait will automatically analyze whether a child process of the current process has exited. If it finds such a child process that has become a zombie, wait will collect the information of the child process, destroy it completely and return; If such a child process is not found, the wait will block here until one appears.

The parameter status is used to save some states when the collected process exits. It is a pointer to type int.

Program example

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

int main(void)
{
    char* s = NULL;
    int n = 0;

    pid_t pid = fork();
    assert(pid != -1);

    if (pid == 0)
    {
        s = "child";
        n = 3;
    }
    else
    {
        s = "parent";
        n = 6;

        int val = 0;
        int id = wait(&val);

        if (WIFEXITED(val))
        {
            printf("id = %d, val = %d\n", id, WEXITSTATUS(val));
        }

    }

    int i = 0; 

    for (i; i < n; ++i)
    {
        printf("s = %s, pid = %d\n", s, getpid());
        
        sleep(3);
    }

    exit(3);
}

Operation results:

First, the parent-child process runs normally

As shown in the blue box below, when the child process ends, the parent process prints the exit code of the child process.
The red line indicates that only the parent process is running now, and there is no dead process.

end

Thanks for watching~

Posted by cornelalexa on Sun, 21 Nov 2021 18:22:12 -0800