这里使用信号的方式背后的想法是什么?

时间:2019-02-03 11:44:47

标签: c signals fork waitpid sigprocmask

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

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

#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 :(得分:2)

sigprocmask(SIG_BLOCK, &chld, NULL);阻止SIGCHLD,以便确保执行while (curprocs >= 42)SIGCHLD处理程序不会中断代码,而在其中更改curprocs支票的中间。

sigsuspends从根本上取消对它的阻止,并等待SIGCHLD(由于您通过了一个空掩码,所以实际上是任何信号),在返回时自动重新对其进行阻塞。

处理程序中的waitpid(-1,/*...*/)获取状态为(通常为终止通知)的待处理子项 any (即-1的意思)的状态,从而使数据进入内核与状态更改相关联的人可以释放。第二个参数是状态更改信息所在的位置,但是由于您通过了NULL,因此该信息将被简单地删除。 WNOHANG意味着如果没有其他状态更改通知,请不要等待。

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