在阅读和学习信号时,我发现了一个程序,该程序以特定方式使用信号。我试过理解它,但是我不确定代码的所有部分如何相互影响。
下面是上面提到的代码,我在遇到困难的地方添加了注释:
#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
的相互作用。
有人可以解释这些行的用途或为什么使用它们吗?
答案 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
调用将阻塞您的进程,直到收到新的通知为止。