wait和waitpid
wait
父进程调用wait函数回收子进程信息,防止出现僵尸进程。
- 阻塞等待子进程退出。
- 回收子进程资源(PCB)。
- 获取子进程结束状态。
- 一次wait调用回收一个子进程退出状态。
WAIT(2) Linux Programmer's Manual WAIT(2)
NAME
wait, waitpid, waitid - wait for process to change state
SYNOPSIS
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
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 statechange is considered to be: the child terminated; 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 immediately.
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.
父进程回收僵尸进程
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main() {
pid_t pid, rpid;
int i;
pid = fork();
if (pid == 0) {
sleep(3);
printf("I'm child pid=%d, ppid=%d\n", getpid(), getppid());
} else if (pid > 0) {
#if 0
//循环执行,因此子进程结束之后父进程没有对子进程资源进行回收
//ps aux能看到Z+的僵尸进程
while (1) {
sleep(1);
printf("I'm parent pid=%d, ppid=%d\n", getpid(), getppid());
}
#else
//阻塞回收子进程
rpid = wait(NULL);
if (rpid == -1) {
perror("wait error");
exit(1);
}
while (1) {
sleep(1);
printf("I'm parent pid=%d, ppid=%d\n", getpid(), getppid());
}
#endif
}
return 0;
}
使用status获取子进程结束状态
wait()函数的参数为一个传出参数,int类型。
- WIFEXITED(status):如果为真,说明子进程正常结束。
- WEXITSTATUS(status):获取子进程退出状态码。
- WIFSIGNALED(status):如果为真,说明子进程异常结束。
- WTERMSIG(status):获取子进程异常终止的信号编号。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#define KILL_SIGNAL 0
int main() {
pid_t pid, rpid;
int i;
int status;
pid = fork();
if (pid == 0) {
printf("I'm child pid=%d, ppid=%d\n", getpid(), getppid());
#if KILL_SIGNAL
sleep(100);
#else
sleep(3);
#endif
exit(13);
} else if (pid > 0) {
//阻塞回收子进程
rpid = wait(&status);
if (rpid == -1) {
perror("wait error");
exit(1);
}
if (WIFEXITED(status)) {
printf("child exit status:%d\n", WEXITSTATUS(status));
}
if (WIFSIGNALED(status)) {
printf("child killed by :%d\n", WTERMSIG(status));
}
while (1) {
sleep(1);
printf("I'm parent pid=%d, ppid=%d\n", getpid(), getppid());
}
}
return 0;
}
~# ./test
I'm child pid=53637, ppid=53636
child exit status:13
I'm parent pid=53636, ppid=23909
/*KILL_SIGNAL等于1时,在另一个终端发送kill命令*/
waitpid
pid_t waitpid(pid_t pid, int *status, int options);
可以指定回收某个pid,可以指定为非阻塞状态(WNOHANG)。后面再补充。