• 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的进程。

      

  • 相关阅读:
    动态规划——E (LIS())最长上升子序列
    动态规划——F 最大矩阵和
    动态规划——I 记忆化搜索
    动态规划——C编辑最短距离
    动态规划——K背包问题
    动态规划——H 最少回文串
    动态规划——G 回文串
    动态规划——J 括号配对问题
    Codeforces4D
    UVa10635
  • 原文地址:https://www.cnblogs.com/418ks/p/11717203.html
Copyright © 2020-2023  润新知