1 wait
1.1 Introduction
The wait function is prototype:
# Include <sys/types. h>/* provides the pid_t type definition */# include <sys/Wait. H> pid_t wait (int * Status)
Once a process calls wait, it immediately blocks itself. Wait automatically analyzes whether a sub-process of the current process has exited. If it finds such a sub-process that has become a zombie, wait will collect information about this sub-process and destroy it completely and return it. If such a sub-process is not found, wait will be blocked until one appears.
The status parameter is used to save some statuses when the collection process exits. It is a pointer to the int type. But if we don't care about how this sub-process died, we just want to destroy it (in fact, in most cases, we will think like this ), we can set this parameter to null, as shown below:
PID = wait (null );
If the call succeeds, wait returns the ID of the collected sub-process. If the call process does not have a sub-process, the call fails. In this case, wait returns-1 and errno is set to echild.
1.2 practice
Next let's use an example to apply wait calls. Fork is called by the system in the program. If you are not familiar with this or have forgotten about it, refer to the previous article process management-related system calls (1).
/* Wait1.c */# include <sys/types. h> # include <sys/Wait. h> # include <unistd. h> # include <stdlib. h> main () {pid_t PC, PR; Pc = fork (); If (Pc <0)/* if an error occurs */printf ("error ocurred! /N "); else if (Pc = 0) {/* if it is a sub-process */printf (" this is child process with PID of % d/N ", getpid (); sleep (10);/* sleep for 10 seconds */} else {/* if it is a parent process */PR = wait (null ); /* Wait here */printf ("I catched a child process with PID of % d/N"), Pr);} exit (0 );}
Compile and run:
$ CC wait1.c-O Wait1 $./wait1this is child process with PID of 1508i catched a child process with PID of 1508
We can obviously note that there is a waiting time of 10 seconds before the results of the first row are printed. This is the time we set for the sub-process to sleep. Only the sub-process wakes up from its sleep, it can exit normally and be captured by the parent process. In fact, no matter how long the sub-process sleeps, the parent process will keep waiting. If you are interested, you can try to modify the value by yourself, see what results will appear.
1.3 parameter status
If the value of the status parameter is not null, wait will take out the status of the sub-process and store it in it. This is an integer (INT ), it indicates whether the sub-process Exits normally or is ended abnormally (a process can also be ended by another process with a signal, which will be introduced in future articles ), and the return value at the normal end, or information about which signal is terminated. Because the information is stored in different binary bits of an integer, It is very troublesome to read it using the conventional method. People have designed a special macro (macro) to complete this work, next, let's take a look at two of the most common ones:
1. The wifexited (Status) macro is used to indicate whether the sub-process Exits normally. If yes, it returns a non-zero value.
(Please note that, although the name is the same, the parameter status here is not the only parameter of wait -- the pointer to the integer status, but the integer pointed to by the pointer. Remember not to confuse it .)
2. wexitstatus (Status) When wifexited returns a non-zero value, we can use this macro to extract the return value of the sub-process. If the sub-process calls exit (5) to exit, wexitstatus (Status) 5 is returned. If the sub-process calls exit (7), wexitstatus (Status) returns 7. Note that if the process does not exit normally, that is, if wifexited returns 0, this value is meaningless.
The following is an example of what we just learned:
/* Wait2.c */# include <sys/types. h> # include <sys/Wait. h> # include <unistd. h> main () {int status; pid_t PC, PR; Pc = fork (); If (Pc <0)/* if an error occurs */printf ("error ocurred! /N "); else if (Pc = 0) {/* sub-process */printf (" this is child process with PID of % d. /n ", getpid (); exit (3);/* the sub-process returns 3 */} else {/* parent process */PR = wait (& status ); if (wifexited (Status) {/* If wifexited returns a non-zero value */printf ("the child process % d exit normally. /n ", Pr); printf (" The return code is % d. /n ", wexitstatus (Status);} else/* If wifexited returns zero */printf (" the child process % d exit abnormally. /n ", Pr );}}
Compile and run:
$ CC wait2.c-O wait2 $./wait2this is child process with PID of 1538.the child process 1538 exit normally. The return code is 3.
The parent process accurately captures the returned value 3 of the child process and prints it out.
Of course, there are more than two macros that process exit state, but most of them are rarely used in normal programming, so it is not a waste of space here, interested readers can refer to Linux man pages to learn about their usage.
2 waitpid
2.1 Introduction
The prototype of waitpid system calling in the Linux function library is:
# Include <sys/types. h>/* provides the pid_t type definition */# include <sys/Wait. H> pid_t waitpid (pid_t PID, int * status, int options)
In essence, the functions of the system call waitpid and wait are exactly the same, but the waitpid has two more user-controlled parameters PID and options, this provides us with a more flexible way of programming. The following two parameters are described in detail:
PID
From the parameter name PID and type pid_t, we can see that what is needed here is a process ID. But when the PID gets different values, it has different meanings here.
When the PID is greater than 0, only the child process whose process ID is equal to the PID is waiting. No matter how many other child processes have ended and exited, as long as the specified child process has not ended, waitpid will keep waiting. When pid =-1, wait for any sub-process to exit without any restrictions. At this time, waitpid and wait play the same role. When pid = 0, wait for any sub-process in the same process group. If the sub-process has been added to another process group, waitpid will not ignore it. PID <-1, wait for any sub-process in a specified process group, the ID of this process group is equal to the absolute value of PID.Options
Options provides some additional options to control waitpid. Currently, only the wnohang and wuntraced options are supported in Linux. These two constants can be connected using the "|" operator, for example:
Ret = waitpid (-1, null, wnohang | wuntraced );
If you do not want to use them, you can set options to 0, for example:
Ret = waitpid (-1, null, 0 );
If the wnohang parameter is used to call waitpid, even if no sub-process exits, it will return immediately and will not wait forever like wait.
However, the wuntraced parameter involves some tracking and debugging knowledge and is rarely used. There is not much to worry about here. Interested readers can check the relevant materials on their own.
As you can see, smart readers may already see the clues-isn't wait a packaged waitpid? Check the <kernel source code directory>/include/unistd. h file 349-352 to find the following program segments:
Static inline pid_t wait (int * wait_stat) {return waitpid (-1, wait_stat, 0 );}
2.2 returned values and errors
The return value of waitpid is slightly more complex than that of wait. There are three cases:
When the returned result is normal, waitpid returns the process ID of the collected sub-process; if the option wnohang is set, and waitpid is called to find that no sub-process has exited to collect, 0 is returned; if an error occurs in the call,-1 is returned, and errno is set to the corresponding value to indicate the error. When the sub-process indicated by the PID does not exist, or the process exists, but not the sub-process that calls the process, waitpid will return an error, and errno is set to echild;
/* Waitpid. C */# include <sys/types. h> # include <sys/Wait. h> # include <unistd. h> main () {pid_t PC, PR; Pc = fork (); If (Pc <0)/* If fork Error */printf ("error occured on forking. /n "); else if (Pc = 0) {/* if it is a sub-process */sleep (10);/* sleep for 10 seconds */exit (0 );} /* if the process is parent */do {Pr = waitpid (PC, null, wnohang);/* If the wnohang parameter is used, waitpid will not wait here */If (Pr = 0) {/* If the sub-process is not collected */printf ("No child exited/N "); sleep (1) ;}}while (Pr = 0);/* If the sub-process is not collected, go back and try again */If (Pr = pc) printf ("successfully get child % d/N", Pr); elseprintf ("some error occured/N ");}
Compile and run:
$ CC waitpid. C-o waitpid $./waitpidno child exitedno child ready get child 1526
After 10 failed attempts, the parent process finally collected the exited child process.
Because this is just an example program, it is inconvenient to write too complicated, so we let the Parent and Child processes sleep for 10 seconds and 1 second, respectively, it means that they work for 10 seconds and 1 second respectively. Both parent and child processes have work to do. The parent process uses the short interval of work to check whether the child process exits. If the child process exits, it is collected.