当子进程先于父进程退出时,如果父进程没有调用 wait() 和 waitpid() 函数,子进程就会进入僵死状态(wait() 和 waitpid() 可理解为父亲用来收替儿子收尸的工具或东西)。如果父进程调用了 wait() 或 waitpid() 函数,就不会使子进程变为僵尸进程。设置僵死状态的目的是为了维护子进程的信息,以便父进程在以后某个时候获取这些信息。这些信息包括子进程的进程ID,终止状态以及资源利用信息(如 CPU 时间,内存使用量等等)。如果一个进程终止,而它的子进程又处于僵死状态,那么它所有僵死的子进程的父进程ID将被重置为 1,即 init 进程,它将负责清理它们,也就是说 init 将 wait 这些僵死进程,从而去除它们的僵死状态。对于僵死的进程,我们显然不愿意将其留存,因为它们占用了内核中的空间,而且最终会导致我们耗尽进程资源。
下面是 wait() 函数的描述与举例:
函数原型:
[C++] 纯文本查看 复制代码
#include <sys/types.h>
pid_t wait(int *stat_loc)
函数描述:
wait() 函数是用于使父进程(也就是调用 wait() 的进程)阻塞,直到一个子进程结束或者该进程接到了一个指定的信号为止。如果该父进程没有子进程或者他的子进程已经结束,则 wait() 就会立即返回。
参数说明:
stat_loc 是一个整型指针,是该子进程退出时的状态。如果 stat_loc 为空,则代表任意状态结束的子进程;如果 stat_loc 非空,子进程的退出状态信息就会写到这个指针所指向的整型中。
返回值:
函数成功时返回子进程的进程号;失败则返回 -1。
测试代码:[C++] 纯文本查看 复制代码
#include
#include
#include
#include
#include
int main()
{
pid_t pid;
char *message;
int n;
int exit_code;
printf("fork program starting\n");
pid = fork();
switch(pid)
{
case -1:
perror("fork failed");
exit(1);
case 0:
message = "This is the child";
n = 5;
exit_code = 88;
break;
default:
message = "This is the parent";
n = 3;
exit_code = 0;
break;
}
for(; n > 0; n--) {
puts(message);
sleep(1);
}
if(pid != 0) {
int stat_val;
pid_t child_pid;
child_pid = wait(&stat_val);
printf("Child has finished: PID= %d\n", child_pid);
if(WIFEXITED(stat_val))
printf("Child exited with code %d\n", WEXITSTATUS(stat_val));
else
printf("Child terminated abnormally\n");
}
exit(exit_code);
}
运行输出:beyes@linux-beyes:~/C/call/wait> ./wait.exe
fork program starting
This is the parent
This is the child
This is the parent
This is the child
This is the parent
This is the child
This is the child
This is the child
Child has finished: PID= 12418
Child exited with code 88 说明:
父进程调用 wait() 后被挂起等待( 此时打开另一个终端,输入命令 ps aux 可以看到父进程的状态为 S ),直到子进程结束为止。子进程正常结束后,wait() 函数返回刚刚结束运行的子进程 pid,宏 WEXITSTATUS 获取子进程的退出码。
在 sys/wait.h 中定义了一些说明状态信息的宏:
WIFEXITED(stat_val)
若子进程正常结束则此宏值非0,若进程异常结束,返回0。
WEXITSTATUS(stat_val)
若 WIFEXITED 非0,则此宏返回子进程中 exit 或 _exit 参数的低 8 位。
WIFSIGNALED(stat_val)
如果子进程异常终止,它就取得一个非0值。
WTERMSIG(stat_val)
如果 WIFSIGNALED 非0,此宏返回子进程异常终止的信号编号。
WIFSTOPPED(stat_val)
如果子进程暂停,它就取得一个非 0 值。
WSTOPSIG(stat_val)
如果 WIFSTOPPED 非0,它返回子进程暂停的信号编号。
如 WEXITSTATUS 在 sys/wait.h 中的定义为:
[C++] 纯文本查看 复制代码 # define WEXITSTATUS(status) __WEXITSTATUS(__WAIT_INT(status))
而 __WAIT_INT(status) 被定义为:
[C++] 纯文本查看 复制代码 define __WAIT_INT(status) (status)
在 /bits/waitstatus.h 中对 __WEXITSTATUS(__WAIT_INT(status)) 定义为:
[C++] 纯文本查看 复制代码 /* If WIFEXITED(STATUS), the low-order 8 bits of the status. */
#define __WEXITSTATUS(status) (((status) & 0xff00) >> 8)
WIFEXITED(stat_val) 宏在 bits/waitstatus.h 中的定义为:
[C++] 纯文本查看 复制代码
/* If WIFSIGNALED(STATUS), the terminating signal. */
#define __WTERMSIG(status) ((status) & 0x7f)
/* Nonzero if STATUS indicates normal termination. */
#define __WIFEXITED(status) (__WTERMSIG(status) == 0)
当使用 WIFEXITED(status) 判断子进程为正常终止时,则可用 WEXITSTATUS(status) 取得子进程传递给 exit(),_exit() 或 _Exit() 参数的低 8 位。 |