C/C++网络编程8——多进程服务器端之销毁僵尸进程

  上一节提到,当子进程执行结束,父进程还在执行,在父进程结束之前子进程会成为僵尸进程,那么怎么销毁僵尸进程呢?父进程主动接收子进程的返回值。

销毁僵尸进程的方法:

  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 < 0) { cout << "fork() failed" << endl; return 0; } if (pid == 0) { return 5; } else { int status = 0; wait(&status); if (WIFEXITED(status)) { // 子进程正常结束 cout << "child return: " << WEXITSTATUS(status) << endl; } sleep(300); } return 0; }

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 < 0) {
        cout << "fork() failed" << endl;
        return 0;
    }

    if (pid == 0) {
        sleep(30);
        return 5;
    } else {
        int status = 0;
        while (!waitpid(pid, &status, WNOHANG)) {
            sleep(3);
            cout << "child proc is not finish" << endl;
        }

        if (WIFEXITED(status)) {    // 子进程正常结束
            cout << "child return: " << WEXITSTATUS(status) << endl;
        }
    }

    return 0;
}

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(-1, &status, WNOHANG);

    if (WIFEXITED(status)) {    // 子进程正常结束
        cout << "child proc finish: " << pid <<" " << WEXITSTATUS(status) << endl;
    }
}

int main()
{
    pid_t pid = fork();
    if (pid < 0) {
        cout << "fork() failed" << endl;
        return 0;
    }

    signal(SIGCHLD, read_child_proc);   // 注册子进程结束信号,当子进程结束时调用read_child_proc函数

    if (pid == 0) {
        return 5;
    } else {
        sleep(30);
        cout << "master proc wake up" << endl;
    }

    return 0;
}

  执行程序发现 master proc wake up并不是等30秒以后才输出,而输出很快,说明当注册子进程结束信号以后,当有子进程执行结束时,会马上唤醒sleep的进程。

  

原文地址:https://www.cnblogs.com/418ks/p/11717203.html