Какова идея использования сигналов здесь? - PullRequest
0 голосов
/ 03 февраля 2019

Читая и изучая сигналы, я обнаружил программу, которая использует сигналы особым образом.Я пытался понять это, но я не уверен, как все части кода взаимодействуют с другой.

Ниже приведен вышеупомянутый код, и я добавил комментарии, где у меня возникают трудности:

#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define CP 5

static volatile int curprocs =0; ; 

static void die() {
    exit(EXIT_FAILURE);
}


static void chldhandler() {
    int e = errno;
    // Why do we use waitpid here? What does it do?
    while(waitpid(-1, NULL, WNOHANG) > 0) {
        curprocs--;
    }
    errno = e;
}


void do_work() {
    time_t t;
    srand((unsigned) time(&t));
    sleep(5+ rand() % 4); 
}

int main() {
    struct sigaction sa = {
        .sa_handler = chldhandler,
        .sa_flags = SA_RESTART,
    };

    sigemptyset(&sa.sa_mask);
    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
    exit(-1);
    }

    while(1) {
    sigset_t chld, empty;
    sigemptyset(&empty);
    sigemptyset(&chld);
    sigaddset(&chld, SIGCHLD);  

    // What do the following lines of code do??
    sigprocmask(SIG_BLOCK, &chld, NULL); 
    while (curprocs >= CP) { // cap for the number of child processes 
        sigsuspend(&empty); 
    }
    curprocs++; 
    sigprocmask(SIG_UNBLOCK, &chld, NULL);

    pid_t p = fork();
    if (p == -1) { 
        return -1;
    }
    if (p == 0) {
        // code for the child processes to execute
        do_work(); 
        die();
    } else {
    // Parent process does nothing 
    }
}
return 0; 
}

Очевидно, что вышеприведенная программа рассчитана на максимальное количество 42 дочерних процессов, выполняющих работу.Всякий раз, когда мы хотим иметь новый дочерний процесс, мы используем fork и настраиваем curprocs.Всякий раз, когда завершается дочерний процесс, вызывается chldhandler () и также корректируется curprocs.

Однако я не понимаю взаимодействия двух sigproc_mask, sigsuspend, waitpid и наших двух signalsets chld, empty.

Может кто-нибудь объяснить, что делают эти строки или почему они используются такими, какие они есть?

1 Ответ

0 голосов
/ 03 февраля 2019

sigprocmask(SIG_BLOCK, &chld, NULL); блоков SIGCHLD, так что вы можете быть уверены, что при выполнении while (curprocs >= 42) обработчик SIGCHLD не прервет код, изменив curprocs в середине проверки.

sigsuspends атомно разблокирует его и ждет SIGCHLD (любой сигнал на самом деле, так как вы передали пустую маску), атомно разблокирует его, когда он вернется.

waitpid(-1,/*...*/) в обработчике пожинаетстатус любой (это означает, что -1) дочерний объект, ожидающий изменения статуса (обычно уведомление о завершении), так что данные, которые ядро ​​связывает с изменением статуса, могут быть освобождены.Вторым аргументом будет то, куда будет отправляться информация об изменении статуса, но поскольку вы передали NULL, информация просто будет отброшена.WNOHANG означает, что не нужно ждать, если больше нет уведомлений об изменении статуса.

Поскольку обработчик запускается в ответ на SIGCHLD, должно быть хотя бы одно уведомление об изменении статуса, но оно можетбыть больше, потому что SIGCHLD s могут объединяться (также возможно, что их нет - если вы вызывали waitpid из обычного контекста, когда SIGCHLD был заблокирован).Вот почему обработчик зацикливается.WNOHANG важен, потому что без него, после получения всех уведомлений об изменении статуса, вызов waitpid блокирует ваш процесс до получения нового уведомления.

...