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

C 这里使用信号的方式背后的想法是什么?,c,signals,fork,waitpid,sigprocmask,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 <

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

以下是上述代码和我添加的注释,我有困难:

#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; 
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义CP 5
静态易失性int curprocs=0;
静态空隙模具(){
退出(退出失败);
}
静态无效chldhandler(){
int e=错误号;
//我们为什么在这里使用waitpid?它做什么?
while(waitpid(-1,NULL,WNOHANG)>0){
curprocs--;
}
errno=e;
}
无效工作{
时间;
srand((未签名)时间(&t));
睡眠(5+rand()%4);
}
int main(){
结构sigaction sa={
.sa_handler=chldhandler,
.sa_标志=sa_重新启动,
};
sigemptyset(和sa.sa_面具);
if(sigaction(SIGCHLD,&sa,NULL)=-1){
出口(-1);
}
而(1){
sigset_t chld,空;
sigeptypyset(&empty);
SIGEPTYSET(&chld);
sigaddset(&chld,SIGCHLD);
//以下代码行的作用是什么??
sigprocmask(SIG_块和chld,空);
while(curprocs>=CP){//cap表示子进程的数量
sigsupspend(&empty);
}
curprocs++;
sigprocmask(SIG_UNBLOCK,&chld,NULL);
pid_t p=fork();
如果(p==-1){
返回-1;
}
如果(p==0){
//要执行的子进程的代码
你工作吗;
模具();
}否则{
//父进程什么也不做
}
}
返回0;
}
显然,上述程序的目的是让最多42个子进程进行工作。每当我们想要有一个新的子进程时,我们就使用fork,并调整
curprocs
。 每当子进程完成时,就会调用chldhandler(),并调整
curprocs

然而,我不理解两个
sigproc_掩码、sigssuspend、waitpid
和我们的两个
信号集chld、empty
之间的相互作用

有人能解释一下这些行是做什么的,或者为什么它们是这样使用的吗?

sigprocmask(SIG_BLOCK,&chld,NULL)块<代码> SigCHLD,这样您就可以确信,当您执行<代码>(Currops>=42) > <代码> SigCHLLD处理程序不会中断代码,在检查的中间更改<代码> Currops<代码> > 

sigshuspends
自动解锁并等待一个
SIGCHLD
(任何信号,因为您传递了一个空掩码),当它返回时自动重新锁定它

处理程序中的
waitpid(-1,/*…*/)
将获取状态更改(通常是终止通知)挂起的任何子级(即-1的意思)的状态,以便释放内核与状态更改关联的数据。第二个参数是状态更改信息的位置,但由于您传递了
NULL
,因此该信息将被删除
WNOHANG
表示如果没有任何状态更改通知,则不要等待


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

注释符号是
/
,而不是“\\”。你编译过这个吗?很可能,它使用
curprocs
创建了一个竞赛条件。
++
-->
运算符不是原子运算符。发布的代码不会编译!。在许多其他问题中,它缺少所需头文件所需的
#include
语句。编译时,始终启用警告,然后修复这些警告。(对于
gcc
,至少使用:
-Wall-Wextra-Wconversion-pedantic-std=gnu11
)注意:其他编译器使用不同的选项生成相同的结果\OT:为了便于可读性和理解:1)一致地缩进代码。在每个左大括号“{”之后缩进。在每个右大括号“}”之前取消缩进。建议每个缩进级别为4个空格。2) 单独的代码块:
用于
如果
其他
执行时…当
通过单个空行切换
案例
默认值
。3) 用2或3个空行分隔函数(保持一致)OT:about:
而(curprocs>=42)
发布的代码包含一些“神奇”数字神奇的数字是没有基础的数字。即42岁。”“魔法”数字使代码更难理解、调试等。建议使用
enum
语句或
#define
语句为这些“魔法”数字指定有意义的名称,然后在整个代码中使用这些有意义的名称。