【发布时间】:2014-03-07 16:45:26
【问题描述】:
我有一个管理子进程(fork、execve)的父进程。我在父级中创建了一个处理程序来捕获来自子级的 SIGCHLD 信号,以便调用waitpid() 并采取适当的措施,例如重新启动子级。
我从sigaction() 的手册页了解到,在信号处理程序中,默认情况下会阻止更多相同类型的信号。我绝对希望这种行为,所以我决定测试它。
我在信号处理程序的末尾放置了一个睡眠(我自己的实现在循环中使用clock_nanosleep() 并在中断时恢复)并向孩子发送了一个 SIGINT。这适时让它退出并将 SIGCHLD 发送给父级。我记录了这个事实并开始睡眠 10 秒钟。现在,我向新孩子发送了另一个 SIGINT(sighandler 第一次重新启动它),并惊讶地看到另一个日志和睡眠发生了。
这怎么可能?当我使用调试器附加到父级时,它清楚地显示两个不同的线程被中断以调用我的信号处理程序,现在都处于睡眠状态。如果这样继续下去,我会用完线程!
我知道将长时间睡眠放入信号处理程序是一件愚蠢的事情,但它确实说明了这一点;我希望看到 /proc/[PID]/status 中标记为待处理的第二个信号,但它已被传递。
这是我的代码的相关部分:
设置 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");
}
标准输出清楚地显示:
(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() 的块掩码中,以鼓励它做正确的事情。
欢迎任何指点!
【问题讨论】:
-
mysleep是做什么的? -
它是在循环中使用
clock_nanosleep()的sleep()的实现,同时它返回EINTR,因此即使被中断也会休眠正确的时间 -
哦,你正在使用多个线程。
-
道歉;我应该说清楚的。是的,
main()设置信号处理程序和工作线程然后进入睡眠状态。其他线程完成工作。 -
在这种情况下,每个线程总是有资格被强制跳转到信号。
标签: c linux multithreading signals