【Linux】Señal SIGCHLD

Tabla de contenido

color naranja

Señal SIGCHLD

Condiciones para generar la señal SIGCHLD:

  • Cuando termina el proceso hijo
  • Cuando el proceso hijo recibe la señal SIGSTOP y se detiene
  • El proceso hijo está detenido y se despierta después de recibir SIGCONT.

Las tres situaciones anteriores enviarán la señal SIGCHLD al proceso principal, y el proceso principal ignorará la señal de forma predeterminada. Pero al captar esta señal, el proceso zombie se puede resolver.

El siguiente es un ejemplo de código,

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <sys/wait.h>

void myFun(int num) {
    
    
    printf("捕捉到的信号 :%d\n", num);
    // 回收子进程PCB的资源
    // while(1) {
    
    
    //     wait(NULL); 
    // }
    while(1) {
    
    
       int ret = waitpid(-1, NULL, WNOHANG);
       if(ret > 0) {
    
    
           printf("child die , pid = %d\n", ret);
       } else if(ret == 0) {
    
    
           // 说明还有子进程活着
           break;
       } else if(ret == -1) {
    
    
           // 没有子进程
           break;
       }
    }
}

int main() {
    
    

    // 提前设置好阻塞信号集,阻塞SIGCHLD,因为有可能子进程很快结束,父进程还没有注册完信号捕捉
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGCHLD);
    sigprocmask(SIG_BLOCK, &set, NULL);

    // 创建一些子进程,使一个父进程创建20个子进程
    pid_t pid;
    for(int i = 0; i < 20; i++) {
    
    
        pid = fork();
        //防止子进程再去创建子进程,不断嵌套
        if(pid == 0) {
    
    
            break;
        }
    }

    if(pid > 0) {
    
    
        // 父进程

        // 捕捉子进程死亡时发送的SIGCHLD信号
        struct sigaction act;
        act.sa_flags = 0;
        act.sa_handler = myFun;
        sigemptyset(&act.sa_mask);
        sigaction(SIGCHLD, &act, NULL);

        // 注册完信号捕捉以后,解除阻塞
        sigprocmask(SIG_UNBLOCK, &set, NULL);

        //死循环使父进程永远不会结束,而子进程结束,就会形成僵尸进程,这时可以通过捕捉SIGCHLD
        while(1) {
    
    
            printf("parent process pid : %d\n", getpid());
            sleep(2);
        }
    } else if( pid == 0) {
    
    
        // 子进程
        printf("child process pid : %d\n", getpid());
    }

    return 0;
}

Los procesos zombies a menudo aparecen porque el proceso principal no ha finalizado pero el proceso secundario sí. En este código, se crean 20 procesos secundarios y, debido a que hay un bucle infinito en el proceso principal, nunca puede terminar. Esto dará como resultado 20 procesos zombies. ¿Cómo afrontar estos 20 procesos zombies?

Por lo tanto, primero debe configurar el conjunto de señales de bloqueo, colocar la señal SIGCHLD en él y luego configurar los datos en su conjunto de señales de bloqueo personalizado en el kernel a través de la función sigprocmask. El proceso padre utiliza la función sigaction para capturar la señal SIGCHLD enviada al proceso padre cuando finaliza el proceso hijo. Cuando el núcleo del proceso padre recibe la señal SIGCHLD, establecerá la posición 17 en la señal pendiente establecida en 1 (solo una vez ), pero al mismo tiempo la señal está bloqueada (porque previamente hemos configurado los datos en nuestro propio conjunto de señales de bloqueo personalizado en el kernel, y la señal SIGCHLD existe en el conjunto de datos personalizado, por lo que la posición 17 en el conjunto de señales de bloqueo del sistema se establece en 1, lo que significa que cuando el conjunto de señales pendientes recibe la señal en la posición 17, el procesamiento se suspenderá hasta que se libere el bloqueo).

Por lo que la posición N° 17 queda en 1, a la espera de ser procesada. Después de registrar la captura de señal, desbloquéela. Porque el bit 17 de la señal pendiente establecida es 1 en este momento y el bloqueo se ha liberado. Por lo tanto, la señal SIGCHLD se envía y es capturada por la función de captura de señal sigaction en el proceso principal. Entonces comenzamos a ejecutar la función de procesamiento correspondiente myFun.

En la función de procesamiento, la función waitpid manejará todos los procesos secundarios finalizados (es decir, procesos zombies). La función waitpid solo puede procesar uno a la vez, pero debido a que está en un bucle infinito, no saldrá del bucle infinito hasta que se procesen todos los procesos secundarios completos.

Comente la primera línea de la función principal para indicar que el conjunto de señales de bloqueo debe configurarse de antemano para bloquear SIGCHLD. Debido a que debemos considerar situaciones extremas, suponiendo que 20 procesos secundarios terminaron hace mucho tiempo, los 20 procesos secundarios terminarán antes de que se registre la captura de la señal. Después del número de registro de la señal, la señal SIGCHLD no se puede capturar y nuestra función de procesamiento personalizado myFun no se puede iniciar. Por lo tanto, el conjunto de señales de bloqueo debe configurarse con anticipación y no se puede configurar en el proceso principal. Estas líneas de código también consumirán una cierta cantidad de tiempo. Puede deberse al tiempo consumido que la función de captura no se haya registrado. y el proceso hijo terminará.

Debido a que el resultado de 20 subprocesos no es fácil de capturar, lo cambié. El resultado en la imagen a continuación es el resultado de 5 procesos. Se puede ver que se crean 5 procesos secundarios uno tras otro y todos se reciclan uno tras otro.
Insertar descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/mhyasadj/article/details/130821061
Recomendado
Clasificación