1. Wait for the process to exit
In Linux, the wait function is used to obtain the end information of the sub-process. The function prototype is as follows:
# Include <sys/Wait. H>
Pid_t wait (int * statloc );
The function that calls wait is blocked until any sub-process of the process ends. Wait retrieves information about the child process and returns the ID of the child process. The marriage complaint information is stored in the statloc parameter. If the process does not have a child process, an error is returned immediately. The returned value is-1. If several child processes have ended running when the wait function is called, the wait function returns immediately, however, the specific information of which sub-process is obtained is not fixed and should be determined based on the return value of the wait function.
Process Termination information and operation macros
Macro for status judgment
Wifexited (Status) wexitstatus (Status)
Wifsignaled (Status) wtermsig (Status)
Process pause wifstopped (Status) wstopsig (Status)
For example, when a process Exits normally and the parent process of the process obtains the end information, you need to determine: if the value of wifexited (Status) is true, it indicates that the process Exits normally, weitstatus (Status) indicates the Process Termination status in the returned information.
Eg:
// Wait. c
# Include <stdio. h>
# Include <stdlib. h>
# Include <unistd. h>
# Include <sys/Wait. H>
Int main (void)
{
Pid_t PID;
Int status;
PID = fork ();
If (PID <0 ){
Perror ("fail to fork ");
Exit (1 );
} Else if (pid = 0 ){
Printf ("the first, exit normally/N ");
Exit (0 );
} Else {/* parent process */
If (wait (& Status) =-1 ){
Perror ("fail to wait ");
Exit (1 );
}
If (wifexited (Status) = 1)
/* Exit normally */
Printf ("the status of first is: % d/N", wexitstatus (Status ));
}
PID = fork ();
If (PID <0 ){
Perror ("fail to fork ");
Exit (1 );
} Else if (pid = 0 ){
Printf ("the second, exit abnormally/N ");
1/0;/* The sigfpe exception signal is generated */
} Else {
/* Parent process */
If (wait (& Status) =-1 ){
Perror ("fail to wait ");
Exit (1 );
}
If (wifsignaled (Status) = 1)
/* Obtain the signal value of the final sub-process */
Printf ("the terminated signal is: % d/N", wtermsig (Status ));
}
Return 0;
}
2. Wait for the specified process
Wait can only wait for the first child process to end. If you need to specify to wait for a child process, use the following code:
While (PID! = Wait (& Status ));
There is another function:
# Include <sys/Wait. H>
Pid_t waitpid (pid_t PID, int * statloc, int options );
PID specifies the process ID of the child process to wait, which has some other functions
PID wait Function
-1. Wait for any sub-process
> 0 wait for the child process with the same process ID and PID
0 wait for sub-processes with the same group ID and PID
<-1 any sub-process in the group whose ID is equal to the absolute value of PID
The meaning of statloc is the same as that in wait
The third is the control option.
Description of wait function options
Wcontinued: when the sub-process continues to run after being paused and its status has not been reported, its status is returned.
Wnohang: The waitpid function returns
Wuntraced: when the sub-process is suspended and its status has not been reported to the country since the suspension, the sub-process will return its status.
This parameter can be set to 0 or "or.
The waitpid function waits for the specified sub-process. If the sub-process is stopped, the return value is the sub-process ID. At this time, if PID> 0, the return value is equal to the value of the PID parameter. If the process has not ended and the wnohang option is set, the return value is-1, if the specified process or process group does not exist or the process specified by the PID parameter is not a child process that calls the waitpid function, an error is returned immediately.
Eg:
// Waitpid. c
# Include <stdio. h>
# Include <stdlib. h>
# Include <unistd. h>
# Include <sys/Wait. H>
Int main ()
{
Pid_t PID;
PID = fork ();
If (PID <0 ){
Printf ("fail to fork/N ");
Exit (1 );
} Else if (pid = 0 ){
Printf ("the child/N ");
Sleep (5 );
Exit (0 );
} Else {
Printf ("the parent/N ");
If (waitpid (PID, null, wnohang) =-1)/* non-blocking waiting for sub-process */
Printf ("the child is not available now/N ");
}
Printf ("no waiting, parent done/N ");
Return 0;
}
3. Zombie Process
The sub-process has exited, but its exit status information is still stored in the kernel, and the process ID is also saved in the system process list. At this time, the process becomes a zombie process.
It cannot be used on behalf of the line, and it does not take up CPU time.
The zombie process will remain in the system until the parent process obtains its end state information (that is, the parent process calls wait ).
Because the zombie process still occupies the ID, when the number of zombie processes reaches a certain level, the system will no longer generate new processes.
Eg:
// Zombie. c
# Include <stdio. h>
# Include <stdlib. h>
# Include <unistd. h>
Int main (void)
{
Pid_t PID;
PID = fork ();
If (PID <0 ){
Printf ("fail to fork/N ");
Exit (0 );
} Else if (pid = 0 ){
Printf ("the child/N ");
Sleep (5 );
Printf ("done/N ");
Exit (0 );
} Else
Printf ("the parent/N ");
Sleep (30);/* during the 30 seconds, the sub-process is a zombie process */
If (wait (null) =-1 ){
Perror ("fail to wait ");
Exit (1 );
}
Return 0;
}
4. Avoid zombie Processes
To avoid zombie processes, you must call the wait function in the parent process. However, consider a server program model that processes interactive client requests:
Socket ();
BIND ();
Listen ();
While (1 ){
Accept ();
If (Fork () = 0) {// create a sub-process to process client-side interactive requests
While (1 ){
Read ();
Process (); // process the request
Write ();
}
Close ();
Exit ();
}
Close ();
}
If the parent process calls the wait function, the parent process will be blocked before the child process exits. Therefore, the server can only process requests from one client at a time.
If the parent process stops running before the child process ends, the child process becomes an orphan process. The INIT process is responsible for the adoption of the orphan process, that is, the INIT process will become the parent process of all the parent processes that exit before themselves. As a system daemon process, the INIT process is designed to call the wait function forever. That is to say, all sub-processes of the INIT process will not become zombie processes. Therefore, this method is used to avoid zombie processes.
# Include <stdio. h>
# Include <stdlib. h>
# Include <unistd. h>
# Include <sys/Wait. H>
Int main (void)
{
Pid_t PID;
PID = fork ();
If (PID <0 ){
Printf ("fail to fork/N ");
Exit (1 );
} Else if (pid = 0 ){
Printf ("the child/N ");
PID = fork (); // create a Sun Tzu process that handles the actual work
If (PID <0 ){
Printf ("fail to fork/N ");
Exit (1 );
} Else if (pid = 0) {// Sun Tzu Process
Printf ("do something you want/N ");
Sleep (5 );
Printf ("done/N ");
Exit (0 );
} Else
Exit (0); // The child process exits and the child process is entrusted to the INIT process.
} Else
Printf ("the parent/N ");
If (wait (null) =-1) {// The parent process calls wait.
Perror ("fail to wait ");
Exit (1 );
}
Return 0;
}
In this way, the above server model is changed to the following form:
Socket ();
BIND ();
Listen ();
While (1)
{
Accept ();
If (Fork () = 0 ){
If (Fork () = 0) {// create a Sun Tzu Process
While (1 ){
Read ()
Process ();
Write ();
}
Close ();
Exit ();
} Else
Exit (); // The child process exits. The child process's parent process changes to the INIT process.
}
Close ();
}
5. output process Statistics
To obtain more information about process execution (such as CPU usage and page error count), you can use the wait3 and wait4 functions, which are similar to the wait and waitpid functions.
# Include <sys/types. h>
# Include <sys/Wait. H>
# Include <sys/time. h>
# Include <sys/source. h>
Pid_t wait3 (int * statloc, int options, struct rusage * rusage );
Pid_t wait4 (pid_t PID, int * statloc, int options, struct rusage * rusage );
More detailed information is stored in rusage.
// Wait3.c
# Include <stdio. h>
# Include <stdlib. h>
# Include <unistd. h>
# Include <sys/types. h>
# Include <sys/Wait. H>
# Include <sys/resource. h>
Int main (void)
{
Pid_t PID;
Struct rusage;
PID = fork ();
If (PID <0 ){
Printf ("fail to fork/N ");
Exit (0 );
} Else if (pid = 0 ){
Printf ("the child/N ");
Exit (0 );
} Else
Printf ("the parent/N ");
If (wait3 (null, 0, & rusage) =-1 ){
Perror ("fail to wait ");
Exit (1 );
}
Printf ("utime is % d", rusage.ru _ utime );
Printf ("stime is % d", rusage.ru _ stime );
Printf ("maxrss is % d", rusage.ru _ maxrss );
Printf ("ixrss is % d", rusage.ru _ ixrss );
Printf ("idrss is % d", rusage.ru _ idrss );
Printf ("isrss is % d", rusage.ru _ isrss );
Printf ("minflt is % d", rusage.ru _ minflt );
Printf ("majflt is % d", rusage.ru _ majflt );
Printf ("nswap is % d", rusage.ru _ nswap );
Printf ("inblock is % d", rusage.ru _ inblock );
Printf ("oublock is % d", rusage.ru _ oublock );
Printf ("msgsnd is % d", rusage.ru _ msgsnd );
Printf ("msgrcv is % d", rusage.ru _ msgrcv );
Printf ("nsignals is % d", rusage.ru _ nsignals );
Printf ("nvcsw is % d", rusage.ru _ nvcsw );
Printf ("nivcsw is % d", rusage.ru _ nivcsw );
Return 0;
}