本節目標:
一,殭屍進程
當一個子進程先於父進程結束運行時,它與其父進程之間的關聯還會保持到父進程也正常地結束運行,或者父進程調用了wait才告終止。
子進程退出時,核心將子進程置為殭屍狀態,這個進程稱為殭屍進程,它只保留最小的一些核心資料結構,以便父進程查詢子進程的退出狀態。
進程表中代表子進程的資料項目是不會立刻釋放的,雖然不再活躍了,可子進程還停留在系統裡,因為它的退出碼還需要儲存起來以備父進程中後續的wait調用使用。它將稱為一個“僵進程”。
二,如何避免殭屍進程
- 調用wait或者waitpid函數查詢子進程退出狀態,此方法父進程會被掛起。
- 如果不想讓父進程掛起,可以在父進程中加入一條語句:signal(SIGCHLD,SIG_IGN);表示父進程忽略SIGCHLD訊號,該訊號是子進程退出的時候向父進程發送的。
三,SIGCHLD訊號
當子進程退出的時候,核心會向父進程發送SIGCHLD訊號,子進程的退出是個非同步事件(子進程可以在父進程啟動並執行任何時刻終止)
如果不想讓子進程編程殭屍進程可在父進程中加入:signal(SIGCHLD,SIG_IGN);
如果將此訊號的處理方式設為忽略,可讓核心把殭屍子進程轉交給init進程去處理,省去了大量殭屍進程佔用系統資源。
樣本:
#include <stdio.h><unistd.h><signal.h><stdlib.h> main((signal(SIGCHLD,SIG_IGN) ===(pid == -(pid == (pid >
結果:
如果成功,wait會返回被收集的子進程的進程ID,如果調用進程沒有子進程,調用就會失敗,此時wait返回-1,同時errno被置為ECHILD。
man協助:
DESCRIPTION
All of these system calls are used to wait for state changes in a child
of the calling process, and obtain information about the child whose
state has changed. A state change is considered to be: the child ter-
minated; the child was stopped by a signal; or the child was resumed by
a signal. In the case of a terminated child, performing a wait allows
the system to release the resources associated with the child; if a
wait is not performed, then the terminated child remains in a "zombie"
state (see NOTES below).
If a child has already changed state, then these calls return immedi-
ately. Otherwise they block until either a child changes state or a
signal handler interrupts the call (assuming that system calls are not
automatically restarted using the SA_RESTART flag of sigaction(2)). In
the remainder of this page, a child whose state has changed and which
has not yet been waited upon by one of these system calls is termed
waitable.
wait() :
The wait() system call suspends execution of the calling process until
one of its children terminates. The call wait(&status) is equivalent
to:
waitpid(-1, &status, 0);
If status is not NULL, wait() and waitpid() store status information in
the int to which it points. This integer can be inspected with the
following macros (which take the integer itself as an argument, not a
pointer to it, as is done in wait() and waitpid()!):
WIFEXITED(status)
returns true if the child terminated normally, that is, by call-
ing exit(3) or _exit(2), or by returning from main().
WEXITSTATUS(status)
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 only be
employed if WIFEXITED returned true.
WIFSIGNALED(status)
returns true if the child process was terminated by a signal.
WTERMSIG(status)
returns the number of the signal that caused the child process
to terminate. This macro should only be employed if WIFSIGNALED
returned true.
WCOREDUMP(status)
returns true if the child produced a core dump. This macro
should only be employed if WIFSIGNALED returned true. This
macro is not specified 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 only possible if the call was done using WUN-
TRACED or when the child is being traced (see ptrace(2)).
WSTOPSIG(status)
returns the number of the signal which caused the child to stop.
This macro should only be employed if WIFSTOPPED returned true.
WIFCONTINUED(status)
(since Linux 2.6.10) returns true if the child process was
resumed by delivery of SIGCONT.
- wait系統調用會使父進程暫停執行,直到它的一個子進程結束為止。
- 返回的是子進程的PID,它通常是結束的子進程
- 狀態資訊允許父進程判定子進程的退出狀態,即從子進程的main函數返回的值或子進程中exit語句的退出碼。
- 如果status不是一個null 指標,狀態資訊將被寫入它指向的位置
可以上述的一些宏判斷子進程的退出情況:
<sys/wait.h><stdlib.h><unistd.h> main(=(pid < (pid == = wait(&(ret <
結果:
<sys/wait.h><stdlib.h><unistd.h> main(=(pid < (pid == = wait(&(ret <
結果:
<sys/wait.h><stdlib.h><unistd.h> main(=(pid < (pid == = waitpid(pid,&(ret <
結果:
可知,option設為WNOHANG,父進程不會等到子進程的退出,即不會阻塞,如果沒有子進程退出則立即返回-1,