我有一个管理子项的父进程(fork,execve)。我在父级中创建了一个处理程序来捕获来自子级的SIGCHLD信号,以便调用waitpid()
并采取适当的操作,例如重新启动子级。
我从sigaction()
的手册页中了解到,在信号处理程序内部,默认情况下会阻止相同类型的其他信号。我绝对希望这种行为,所以我决定测试它。
我在信号处理程序结束时将一个睡眠(我自己的实现使用clock_nanosleep()
在循环中恢复),并将SIGINT发送给子节点。这正式退出并将SIGCHLD发送给父母。我记录了这个事实并开始睡了10秒钟。现在,我向另一个孩子发送了另一个SIGINT(sighandler第一次重新启动它),并且惊讶地看到另一个日志和睡眠发生。
这怎么可能?当我使用调试器连接到父节点时,它清楚地显示两个不同的线程被中断以调用我的信号处理程序,两者现在都处于睡眠状态。如果这种情况继续存在,我将耗尽线程!
我知道将长时间的睡眠放入信号处理程序是一项愚蠢的事情,但它确实说明了这一点;我希望在/ proc / [PID] /状态中看到第二个信号标记为待处理,但它已经交付。
以下是我的代码的相关部分:
设置SIGCHLD处理程序:
typedef struct SigActType {
struct sigaction act;
int retval;
void (*func)(int);
}SigActType;
static SigActType sigActList[64];
public void setChildHandler(void (*func)(int)) {
SigActType *sat = &sigActList[SIGCHLD];
sat->act.sa_sigaction = sigchldHandler;
sigemptyset(&sat->act.sa_mask);
sigaddset (&sat->act.sa_mask, SIGTERM);
sigaddset (&sat->act.sa_mask, SIGINT);
sigaddset (&sat->act.sa_mask, SIGCHLD);
sat->act.sa_flags = SA_SIGINFO;
sat->retval = 0;
sat->func = func;
sigaction(SIGCHLD, &sat->act, NULL);
}
static void sigchldHandler(int sig, siginfo_t *si, void *thing) {
SigActType *sat = &sigActList[SIGCHLD];
if (sat->func) {
sat->func(si->si_pid);
}
}
并使用此:
int main(int argc, char **argv) {
setChildHandler(manageChildSignals);
...
}
static void manageChildSignals(int d) {
if ((pid = waitpid(-1, &stat, WAIT_MYPGRP)) > 0) {
... restart child if appropriate
}
printf("start of pause...\n");
mySleep(10);
printf("end of pause...\n");
}
Stdout清楚地表明:
(when I type kill -2 [PID]
start of pause
(when the new child is started and I type kill -2 [NEWPID]
start of pause
...10 seconds slide past...
end of pause
end of pause
我很困惑为什么会这样。如您所见,我甚至将SIGCHLD添加到sigaction()
的阻止掩码中,以试图鼓励它做正确的事情。
欢迎任何指示!
答案 0 :(得分:2)
默认情况下会阻止相同类型的信号。
是的,但仅从线程sigaction()
调用。
来自man sigaction
(粗体强调我):
sa_mask指定应该阻止的信号掩码(即, 添加到信号处理程序所在线程的信号掩码 在执行信号处理程序期间调用。
由于信号处理是按进程进行的,否则任何其他未阻塞相关信号的线程都可能会收到它,即中断并处理它。
如果这种行为不是您想要的,您可能应该修改程序处理信号的方式的设计,使得每个默认情况下所有信号都被阻塞,并且只有一个特定线程的信号接收未被阻塞。
<强>更新强>
信号掩码由子线程从父线程继承。
如果信号处理仅由一个特定线程完成,则主线程在创建任何其他线程之前阻止所有信号。然后创建一个特定的线程来进行信号处理,并让这个线程解锁要处理的信号。这个概念还允许模型像每个信号一个线程。
在mutlithreaded环境中,使用pthread_sigmask()
来屏蔽每个线程基础上的信号。
请注意,多线程进程中sigprocmask()
的行为未指定,然后使用pthread_sigmask()
。