Article From:https://www.cnblogs.com/beixiaobei/p/9064815.html

1、concept

1、Orphan process: a parent process withdraws, and one or more sub processes are still running, so those sub processes will become orphan processes. The orphan process will be adopted by the init process (process number 1) to ensure that every process has a parent process. And the Init process automatically wait its childrenProcess, so all processes taken over by Init will not become a zombie process.

      Supplement: orphan process is a process without parent process, and the responsibility of orphan process falls on the init process. Whenever an orphan process occurs, the kernel sets the parent process of the orphan process to init, and the init process circulate wait () its already exited subprocess.Thus, when an orphan process ends its life cycle, the init process will deal with all its aftermath. Therefore, the process of orphans will not have any harm.

 

2、A zombie process: a process uses fork to create a child process, and if the child process exits, and the parent process does not call wait or waitpid to get the state information of the child process, then the process descriptors of the subprocess are still stored in the system, which is called the zombie process. When using the PS command viewWhen we observe the execution state of the process, we see that the status bar of these processes is defunct. The zombie process is a long dead process, but it still occupies a place in the processs table (slot).

      Supplementation (kernel): after a process terminates, the kernel releases all storage areas used by the terminating process (called exit system calls), and all open files are closed. However, the kernel stores a certain amount of information for each ending child process, and sets the dead state to maintain the information of the sub process, so that the parent can enter.The process is obtained at a later time, which includes at least the process ID, the terminating state of the process, and the CPU time used by the process, so that information can be obtained when the parent process of terminating the child calls wait or waitpid. Any of the sub processes (except init) in eXit does not disappear immediately. Instead, it leaves a data structure called the external zombie process waiting for the parent process to process. This is the stage that every child process must experience. The other child will send a SIGCHLD signal to its parent process when it exits.

 

      Strictly speaking, the zombie process is not the root cause of the problem. The culprit is the parent process that generates lots of zombie processes. As a result, the kill of the parent process that generates a large number of zombie processes is dropped (by sending SIGTERM or SIGKILL signals via kill).The process becomes an orphan process, the orphan process will be taken over by the init process, and the init process will wait () the orphans process and release the resources in the system process table that they occupy.

 

2、How to avoid the zombie process?

(1)Signal (SIGCHLD, SIG_IGN) is notified that the kernel is not concerned about the end of the child process, and is recovered by the kernel. IfDo not want the father process to hang up,A statement can be added to the parent process: signal (SIGCHLD, SIG_IGN); that the parent process ignores the SIGCHLD signal, which is sent to the parent process when the subprocess exits.

(2)The parent process calls wait/waitpid and other functions to wait for the child process to end, if there is no child process to exit.waitCauses the parent process to blockwaitpidYou can pass the WNOHANG to enable the parent process to resume without blocking.

(3)If the parent process is busy, you can use signal to register the signal processing function, call the wait/waitpid processing function, and wait for the child process to exit.

(4)Call fork by two times. The parent process first calls fork to create a child process, and then waitpid waits for the child process to exit. The sub process then fork a grandson process to quit. This process will be recovered by the parent process after the process is withdrawn, and for the grandson process, the parent process has been withdrawn, so Sun Jin.Cheng becomes an orphan process. Orphan process is taken over by the init process. After the sun process is over, init will wait for recycling.

      The first method ignores the SIGCHLD signal, which is often used as a technique for concurrent servers, because concurrent servers often fork many subprocesses, and the server process is needed to clean up the resources by the server process after the subprocess is terminated. If the processing of this signal is ignored, the kernel will be allowed to enter the corpse.The process is transferred to the init process to save a lot of zombie processes from occupying system resources.

 

3、wait()、waitpid()

wait()

Function prototype:
#include <sys/types.h>  
#include <sys/wait.h> 
pid_t wait(int *status)
Working principle:

(1)At the end of the sub process, the system sends SIGCHILD signals to its parent process.

(2)The parent process calls the wait function to block;

(3)The parent process is awakened by the SIGCHILD signal, and then the zombie child process is recovered.

(4)The parent and child process is asynchronous, and the SIGCHILD signal mechanism is to solve the asynchronous communication problem between the parent and child process, so that the parent process can recover the zombie child process in time.

(5)If the parent process does not have any sub processes, wait returns an error.

 
Effect:
Once the process calls wait, it immediately blocks itself until there is a signal coming or the end of the child process. If there is a signal to come or let it find a subprocess that has become a zombie, wait will collect the information of the subprocess and return it completely after it is destroyed; if no such one is foundThe child process, wait will keep blocking until there is one appearance; if the child process is finished when wait is called, wait will return immediately.
 
Parameters:
statusIt is used to save some of the states when the collection process exits, it is a pointer to the int type, indicating that the child process is normal exit or unnormally ended, and the return value at the normal end, or which signal is ended. But if you don’t care how this process dies, just think about it.If you eliminate this zombie process, you can set this parameter to NULL:
pid = wait(NULL); 
 
Return value:
If successful, wait returns the process ID of the collected subprocess, and if the process does not have a subprocess, the call will fail, and the wait returns to -1, and errno is set to ECHILD.

 

Get status information:

Since status information is stored in a different binary bit of an integer, different platforms have different definitions, so it is very troublesome to read in a regular way, and people have designed a set of specialized macros (macro) to do the work, the most commonly used is:

(1)WIFEXITED(status) This macro is used to indicate whether the child process isNormal withdrawal(It is not a signal induced exit, if it is, it will return a non zero value. The parameter status is an integer that the wait parameter pointer points to.

(2)WEXITSTATUS(status) When WIFEXITED returns non zero values, you can use this macro to extract the return value of the child process. If the subprocess calls exit (5) exit, WEXITSTATUS (status) returns 5; if the subprocess calls exit (7), WEXITSTATUS (status) returns 7. Please note that if the process does not exit normally, that is to say, WIFEXITED returns 0, this value is meaningless.

Rest:

(1)WIFSTOPPED/WSTOPSIG:WIFSTOPPED (status) is true when a subprocess is returned when a signal is suspended, and in this case, WSTOPSIG (status) returns the number of the pause child process signal.

(2)WIFCONTINUED:When a pause child is awakened by signal SIGCONT and returns to the state, WIFCONTINUED (status) is true, otherwise it is false.

(3)WIFSIGNALED/WTERMSIG/WCOREDUMP:ProgramAbnormal terminationWhen WIFSIGNALED (staus) is true, WTERMSIG (status) returns the signal number that terminates the process. And if the core file is generated when the program terminates, WCOREDUMP (status) is true, otherwise it isFalse.

 

waitpid()

Function prototype:

#include <sys/types.h>
#include<sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int options);

Effect:

The system call waitpid is the encapsulation of wait. Waitpid just has two more user controlled parameters PID and options, which provides flexibility for programming.

 

Parameters:

(1)pid

pid>0At the time, only the process ID is equal to the child process of PID, no matter how many other sub process runs are out, as long as the specified subprocess is not over, waitpid will be kept waiting.

pid=-1When you wait for any sub process to exit, there is no restriction. At this point, the function of waitpid and wait is exactly the same.

pid=0When waiting for any sub process in the same process group, waitpid will not pay any attention to it if the sub process has joined other process groups.

pid<-1When you wait for any subprocess in a specified process group, the ID of this process group is equal to the absolute value of PID.

(2)options

If WNOHANG parameters are used, even if no child processes exit, it will return immediately, and will not wait forever as wait does.

If the WUNTRACED parameter is used, the child process goes back to the pause immediately, but the end state is ignored.

LinuxIt only supports two options of WNOHANG and WUNTRACED, which are two constants, and can be linked together by using “operator”.

ret=waitpid(-1,NULL,WNOHANG | WUNTRACED);

If you don’t want to use them, you can set options to 0, such as ret=waitpid (-1, NULL, 0).

 

Return value:

(1)When normal returns, waitpid returns the process ID of the collected sub processes.

(2)If the option WNOHANG is set, and the waitpid in the invocation finds that the child process that has not been withdrawn can be collected, it returns 0.

(3)If there is an error in the call, -1 is returned, and errno will be set to the corresponding value to indicate the error.

(4)When the subprocess indicated by PID does not exist, or this process exists, but not the process’s subprocess, the waitpid will go wrong, and then the errno is set to ECHILD.

 

Get the status information (as above):

WIFEXITED(status):If the subprocess ends normally, it is not 0.
WEXITSTATUS(status):ObtainZi JinCourseexit()The return code is usually used to determine whether WIFEXITED is normally terminated before using this macro.
WIFSIGNALED(status):If the child process is finished because of the signal, the macro value is true.
WTERMSIG(status):The signal code that gets the child process to stop because of the signal is usually judged by WIFSIGNALED before using this macro.
WIFSTOPPED(status):If the child process is suspended, the macro value is true. This is usually the case only when using WUNTRACED.
WSTOPSIG(status):The code for obtaining the stop signal of the boot process is usually used first.WIFSTOPPED Use this macro until you are judged.
 

4、Experiment

Many experiments have been conducted below to understand the multiple processes of parent process wait.

#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
    pid_t pid;
    if(fork() == 0)
    {
        printf("1--This is the child process. pid =%d\n", getpid());
        sleep(3);
        printf("%d exit\n", getpid());
        exit(0);
    }
    if(fork() == 0)
    {
        printf("2--This is the child process. pid =%d\n", getpid());
        sleep(10);
        printf("%d exit\n", getpid());
        exit(0);
    }
    if(fork() == 0)
    {
        printf("3--This is the child process. pid =%d\n", getpid());
        sleep(17);
        printf("%d exit\n", getpid());
        exit(0);
    }
    // while(1)
    // {
    //     pid = wait(NULL);
    //     printf("parent:%d,return of wait:%d\n", getpid(), pid);
    //     if(pid == -1)
    //     {
    //         break;
    //     }
    // }
    //Loop wait each sub process output, the last return value is -1 indicating that there is no child process, and the parent process also withdraws.//while (wait (NULL)! = -1);After the last sub process of //wait is withdrawn, the parent process withdraws.//printf ("parent:%d, return of wait:%d\n", getpid (), wait (NULL);After the first process returned by //wait, the parent process returns.Other processes that do not return to the orphan process are taken over by the init process./ / while (wait (NULL)! = -1)/ / {/ / printf ("parent:%d, returN of wait:%d\n ", getpid (), wait (NULL));/ /}//while wait first exit process, printf wait second sub processes output, whileThen wait third sub processes, finally printf is -1, indicating that there is no child process, the parent process exit.Signal (SIGCHLD, SIG_IGN); / / ignores the sub process exit, and the kernel is directly transferred to init to process defunc.T, so even if the parent process does not quit, there will be no zombie process.Sleep (20); / / / / the parent process does not have any subprocesses of wait, no SIG_IGN is set, and the sub process is exited when it is running, and all subprocesses turn to the zombie process until the parent process is out of the process.The subprocess is taken over by the init processPrintf ("exit\n");Return 0;}

 

Summary:

Call a wait, then the first child process returns after the first subprocess returns, and the other subprocesses are still running, why not the zombie process, but directly from the init

—–The parent process is returned, so the other sub processes become orphan processes and are directly taken over by init, so PS – EF grep defunct does not have a zombie process.

 

If the parent process fork is more than a sub process, the child process is still running after the child process is out, but without any subprocesses of wait, then the subprocess will change the zombie process until the parent process ends, and then the init process takes over.

—–The parent process is not blocked by wait and is still running after the child process is finished. In order not to produce a zombie process, signal (SIGCHLD, SIG_IGN) can be set in the parent process; the parent process ignores the subprocess exit, and the child process is directly transferred to the init takeover.

 

Conceptual reference:

https://www.cnblogs.com/wuchanming/p/4020463.html

https://www.cnblogs.com/Anker/p/3271773.html 

https://blog.csdn.net/astrotycoon/article/details/41172389

http://blog.51cto.com/no001/493589

https://www.jianshu.com/p/e0c6749dbcdc

Link of this Article: Multi process wait

Leave a Reply

Your email address will not be published. Required fields are marked *