1 wait/waitpid
僵屍程序:
子程序退出,父程序沒有回收子程序資源(pcb),則子程序變成僵屍程序
孤兒程序:
父程序先于子程序結束,則子程序成為孤兒程序,子程序的父程序成為1号
程序init程序,稱為init程序領養孤兒程序
2依賴的頭檔案
#include <sys/types.h>
#include <sys/wait.h>
3函數聲明
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, intoptions);
the value of pid can be:
< -1
meaning wait for anychild process whose process
group id is
equal to the absolute value ofpid.
-1
meaning wait for any childprocess.
meaning wait for
any child process whose process group id is
equal to that of the callingprocess.
> 0
meaning wait for thechild whose process id
is equal to
the
value of pid.
< -1
回收指定程序組内的任意子程序
-1
回收任意子程序
回收和目前調用waitpid一個組的所有子程序
> 0
回收指定id的子程序
3.說明:
一個程序在終止時會關閉所有檔案描述符,釋放在使用者空間配置設定的記憶體,但它的pcb還
保留着,核心在其中儲存了一些資訊:如果是正常終止則儲存着退出狀态,如果是異常終止
則儲存着導緻該程序終止的信号是哪個。這個程序的父程序可以調用wait或waitpid擷取這
些資訊,然後徹底清除掉這個程序。我們知道一個程序的退出狀态可以在shell中用特殊變
量$?檢視,因為shell是它的父程序,當它終止時shell調用wait或waitpid得到它的退出狀
态同時徹底清除掉這個程序。
如果一個程序已經終止,但是它的父程序尚未調用wait或waitpid對它進行清理,這時
的程序狀态稱為僵屍(zombie)程序。任何程序在剛終止時都是僵屍程序,正常情況下,僵
屍程序都立刻被父程序清理了,為了觀察到僵屍程序,我們自己寫一個不正常的程式,父進
程fork出子程序,子程序終止,而父程序既不終止也不調用wait清理子程序:
#include <unistd.h>
#include <stdlib.h>
int main(void)
{
pid_t pid=fork();
if(pid<0) {
perror("fork");
exit(1);
}
if(pid>0) { /* parent */
while(1);
/* child */
return 0;
若調用成功則傳回清理掉的子程序id,若調用出錯則傳回-1。父程序調用wait或
waitpid時可能會:
*
阻塞(如果它的所有子程序都還在運作)。
帶子程序的終止資訊立即傳回(如果一個子程序已終止,正等待父程序讀取其終止信
息)。
出錯立即傳回(如果它沒有任何子程序)。
這兩個函數的差別是:
如果父程序的所有子程序都還在運作,調用wait将使父程序阻塞,而調用waitpid時如果在options參數中指定wnohang可以使父程序不阻塞而立即傳回0。
* wait等待第一個終止的子程序,而waitpid可以通過pid參數指定等待哪一個子程序。
可見,調用wait和waitpid不僅可以獲得子程序的終止資訊,還可以使父程序阻塞等待子進
程終止,起到程序間同步的作用。如果參數status不是空指針,則子程序的終止資訊通過
這個參數傳出,如果隻是為了同步而不關心子程序的終止資訊,可以将status參數指定為
null。
例waitpid
the value
of options is an or of zero or more of the following con‐
stants:
wnohang
return immediately ifno child has exited.
wuntraced
also return if a childhas stopped
(but not traced
via
ptrace(2)). status for traced children which havestopped
is provided even if thisoption is not specified.
wcontinued (since linux 2.6.10)
also return if a stoppedchild has been resumed by delivery
of sigcont.
(for linux-only options, see below.)
if status is not null, wait() and waitpid()store status information in
the int to which it points.
thisinteger can be inspected with
following
macros (which take the integer itself as anargument, not a
pointer to it, as is done in wait() and waitpid()!):
wifexited(status)
returns true if the childterminated normally, that is, by call‐
ing exit(3) or _exit(2), or byreturning from main().
wexitstatus(status)
returns the exit
status of thechild.
this consists of the
least significant 8 bits of thestatus argument that
the child
specified in a
call to exit(3) or _exit(2) oras the argument
for a return statement inmain(). this macro should be employed
only if wifexited returned true.
wifsignaled(status)
returns true if the child processwas terminated by a signal.
wtermsig(status)
returns the number of the signal that caused the child process
to terminate. this macro should be employed only ifwifsignaled
returned true.
wcoredump(status)
returns true if
the child produced a core dump.
this macro
should be employed only if wifsignaled
returned true. this
macro is notspecified in posix.1-2001 and is not available on
some unix implementations (e.g.,aix, sunos).
only use this
enclosed in #ifdef wcoredump ...#endif.
wifstopped(status)
returns true if the child process was stopped by delivery of a
signal; this is possible only ifthe call was done
using wun‐
traced or when the child is beingtraced (see ptrace(2)).
wstopsig(status)
returns the number of the signalwhich caused the child to stop.
this macro should be employedonly if wifstopped returned true.
wifcontinued(status)
(since linux 2.6.10) returns true if
the child process
was
resumed by delivery of sigcont.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int
main(int argc, char *argv[])
{
pid_t cpid, w;
int status;
cpid = fork();
if (cpid == -1) {
exit(exit_failure);
}
if (cpid == 0) {
/*code executed by child */
printf("child pid is%ld\n", (long) getpid());
if (argc == 1)
pause(); /* wait for signals */
_exit(atoi(argv[1]));
} else {
/*code executed by parent */
do {
w = waitpid(cpid,&status, wuntraced | wcontinued);
if (w == -1) {
perror("waitpid");
if (wifexited(status)) {
printf("exited,status=%d\n", wexitstatus(status));
} else if(wifsignaled(status)) {
printf("killed by signal%d\n", wtermsig(status));
} else if(wifstopped(status)) {
printf("stopped bysignal %d\n", wstopsig(status));
} else if(wifcontinued(status)) {
printf("continued\n");
} while (!wifexited(status)&& !wifsignaled(status));
exit(exit_success);
}