上一节提到,当子进程执行结束,父进程还在执行,在父进程结束之前子进程会成为僵尸进程,那么怎么销毁僵尸进程呢?父进程主动接收子进程的返回值。
销毁僵尸进程的方法:
1:使用wait函数
2:使用waitpid函数
3:利用信号
1:使用wait函数销毁僵尸进程
#include <sys/wait.h> pid_t wait(int *status);
// 成功返回终止的子进程id,失败返回-1
在父进程中调用wait函数以后,如果有子进程已经执行结束,那么子进程传回的返回值将存储到status所指的内存中,但是如果没有子进程执行结束,父进程将会阻塞在wait函数,直到有子进程执行结束,这是一种不好的实现方法。
// wait函数销毁僵尸进程
#include <iostream>
#include <unistd.h>
#include <sys/wait.h> using namespace std; int main()
{
pid_t pid = fork();
if (pid < ) {
cout << "fork() failed" << endl;
return ;
} if (pid == ) {
return ;
} else {
int status = ;
wait(&status);
if (WIFEXITED(status)) { // 子进程正常结束
cout << "child return: " << WEXITSTATUS(status) << endl;
} sleep();
} return ;
}
2:使用waitpid函数销毁僵尸进程
wait函数会使程序阻塞,可换用waitpid函数杀死僵尸进程,同时能避免程序阻塞。
#include <sys/wait.h> pid_t waitpid(pid_t pid, int *status, int options);
// 成功返回终止的子进程id,失败返回-1
// pid : 等待终止的子进程id,传-1代码任意子进程终止
// status:和wait函数的参数一样
// options:传递WNOHANG,没有终止的子进程也不进入阻塞状态,返回0
#include <iostream>
#include <unistd.h>
#include <sys/wait.h> using namespace std; int main()
{
pid_t pid = fork();
if (pid < ) {
cout << "fork() failed" << endl;
return ;
} if (pid == ) {
sleep();
return ;
} else {
int status = ;
while (!waitpid(pid, &status, WNOHANG)) {
sleep();
cout << "child proc is not finish" << endl;
} if (WIFEXITED(status)) { // 子进程正常结束
cout << "child return: " << WEXITSTATUS(status) << endl;
}
} return ;
}
3:利用信号销毁僵尸进程
利用wait函数能销毁僵尸进程,但是会阻塞父进程;利用waitpid也能销毁僵尸进程并且不阻塞父进程,但是也需要不停的去检查子进程结束没有。所以wait及waitpid方式都不完美。于是引入了信号,信号是在特定事件发生时由操作系统向进程发送的消息,接收到消息的进程做信号处理。信号的使用方法是先注册信号,告诉操作系统,当某个信号发生时,要做什么事情。
signal(SIGCHLD, do_what); SIGCHLD是子进程结束的信号,当子进程结束时,执行do_what函数。
其他常用信号,SIGALRM:已到通过调用alarm函数注册的时间;SIGINT:输入CTRL+C
#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h> using namespace std; void read_child_proc(int sig)
{
int status;
pid_t pid = waitpid(-, &status, WNOHANG); if (WIFEXITED(status)) { // 子进程正常结束
cout << "child proc finish: " << pid <<" " << WEXITSTATUS(status) << endl;
}
} int main()
{
pid_t pid = fork();
if (pid < ) {
cout << "fork() failed" << endl;
return ;
} signal(SIGCHLD, read_child_proc); // 注册子进程结束信号,当子进程结束时调用read_child_proc函数 if (pid == ) {
return ;
} else {
sleep();
cout << "master proc wake up" << endl;
} return ;
}
执行程序发现 master proc wake up并不是等30秒以后才输出,而输出很快,说明当注册子进程结束信号以后,当有子进程执行结束时,会马上唤醒sleep的进程。