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
语句为这些“魔法”数字指定有意义的名称,然后在整个代码中使用这些有意义的名称。