1

在阅读和学习信号时,我发现了一个以特定方式使用信号的程序。我试着理解它,但我不确定代码的所有部分如何与另一个部分交互。

下面是上面提到的代码,我添加了注释,我遇到了困难:

#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 和 adjust curprocs。每当子进程完成时,都会调用 chldhandler() 并curprocs进行调整。

但是我不明白两者sigproc_mask, sigsuspend, waitpid和我们两个的相互作用signalsets chld, empty

有人可以解释这些行的作用或为什么要这样使用它们吗?

4

1 回答 1

2

sigprocmask(SIG_BLOCK, &chld, NULL);SIGCHLD,这样您就可以确保在您执行while (curprocs >= 42)此操作时,SIGCHLD处理程序不会中断代码,而是curprocs在检查中间进行更改。

sigsuspends原子地解除阻塞并等待一个SIGCHLD(实际上是任何信号,因为您传递了一个空掩码),当它返回时原子地重新阻塞它。

waitpid(-1,/*...*/)处理程序中的 in 获取任何状态更改(通常是终止通知)未决的子级(这就是 -1 的含义)的状态,以便可以释放内核与状态更改相关联的数据。第二个参数将是状态更改信息的去向,但由于您通过了NULL,该信息将被简单地删除。WNOHANG表示如果没有更多状态更改通知,请不要等待。

由于处理程序是响应 运行的SIGCHLD,因此应该至少有一个状态更改通知,但可能还有更多,因为SIGCHLDs 可以合并(也可能没有任何通知 - 如果您在被阻止waitpid时从正常上下文调用)。SIGCHLD这就是处理程序循环的原因。这WNOHANG很重要,因为没有它,在收到所有状态更改通知之后,waitpid调用将阻塞您的进程,直到有新通知到达。

于 2019-02-03T12:49:31.787 回答