发送多个信号时发生主机错误
master error when multiple signal are sent
我遇到了这个问题:
我用 c 编写了一个程序,其中主进程创建了一些子进程,这些子进程在一段时间后能够向主进程发送信号:
信号使用此代码发送:
kill(getppid(), SIGUSR1);
而主进程,在 while 循环中正在等待 SIGUSR1 消息...
一切都很好,但如果我增加子编号并自动同时有更多信号的可能性,程序会崩溃并打印消息:
用户自定义信号1
主要代码是这样的:
void signalHandler(int sig, siginfo_t* info, void* vp) {
if (sig == SIGUSR1) {
printf("SIGUSR1 has arrived\n");
} else if (sig == SIGUSR2) {
printf("SIGUSR2 has arrived\n");
}
}
int main(int argc, char const *argv[]) {
struct sigaction action, old_action;
memset(&action, 0, sizeof(struct sigaction));
action.sa_sigaction = signalHandler;
sigemptyset(&action.sa_mask);
action.sa_flags = SA_RESTART | SA_NODEFER;
while (1) {
sigaction(SIGUSR1, &action, &old_action);
sigaction(SIGUSR2, &action, &old_action);
}
}
我认为问题是当 master 仍在处理前一个信号时发送信号...但是我该如何解决这个问题
非常感谢
这意味着 child 在 parent 进程能够调用 sigaction()
来配置信号处理程序之前发送信号。发生这种情况时,对 SIGUSR1 的默认信号反应会终止程序:
SIGUSR1 P1990 Term User-defined signal 1
https://man7.org/linux/man-pages/man7/signal.7.html
但是,您的代码存在很多问题。 printf()
在信号处理程序中调用是不安全的(它是 POSIX 定义的 AS-Unsafe):
https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/V2_chap02.html#tag_15_04_03
此外,使用 SA_NODEFER
可能会创建嵌套信号(另一个信号处理程序被调用,而某些信号处理程序是 运行ning),但您的程序无法防止泛洪。给定足够的 children 这将产生堆栈溢出。最后,主程序保持 运行ning 一个 non-stop 无限循环重新配置信号,而它应该只在循环外配置一次并在循环内阻塞(例如 sigwait()
或 pselect()
):
https://man7.org/linux/man-pages/man2/select.2.html
最后,如果您预计 运行 大量 children 可能会用信号淹没 parent,那么最好使用实时信号生成函数 (sigqueue()
) 而不是 kill()
。不同之处在于,使用 sigqueue()
,所有信号都会排队,并且不需要 SA_NODEFER
来避免丢弃信号,而其他一些信号处理程序是 运行ning:
https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/V2_chap02.html#tag_15_04_02
最终结论:代码应该完全重写。
我遇到了这个问题:
我用 c 编写了一个程序,其中主进程创建了一些子进程,这些子进程在一段时间后能够向主进程发送信号:
信号使用此代码发送:
kill(getppid(), SIGUSR1);
而主进程,在 while 循环中正在等待 SIGUSR1 消息...
一切都很好,但如果我增加子编号并自动同时有更多信号的可能性,程序会崩溃并打印消息:
用户自定义信号1
主要代码是这样的:
void signalHandler(int sig, siginfo_t* info, void* vp) {
if (sig == SIGUSR1) {
printf("SIGUSR1 has arrived\n");
} else if (sig == SIGUSR2) {
printf("SIGUSR2 has arrived\n");
}
}
int main(int argc, char const *argv[]) {
struct sigaction action, old_action;
memset(&action, 0, sizeof(struct sigaction));
action.sa_sigaction = signalHandler;
sigemptyset(&action.sa_mask);
action.sa_flags = SA_RESTART | SA_NODEFER;
while (1) {
sigaction(SIGUSR1, &action, &old_action);
sigaction(SIGUSR2, &action, &old_action);
}
}
我认为问题是当 master 仍在处理前一个信号时发送信号...但是我该如何解决这个问题
非常感谢
这意味着 child 在 parent 进程能够调用 sigaction()
来配置信号处理程序之前发送信号。发生这种情况时,对 SIGUSR1 的默认信号反应会终止程序:
SIGUSR1 P1990 Term User-defined signal 1
https://man7.org/linux/man-pages/man7/signal.7.html
但是,您的代码存在很多问题。 printf()
在信号处理程序中调用是不安全的(它是 POSIX 定义的 AS-Unsafe):
https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/V2_chap02.html#tag_15_04_03
此外,使用 SA_NODEFER
可能会创建嵌套信号(另一个信号处理程序被调用,而某些信号处理程序是 运行ning),但您的程序无法防止泛洪。给定足够的 children 这将产生堆栈溢出。最后,主程序保持 运行ning 一个 non-stop 无限循环重新配置信号,而它应该只在循环外配置一次并在循环内阻塞(例如 sigwait()
或 pselect()
):
https://man7.org/linux/man-pages/man2/select.2.html
最后,如果您预计 运行 大量 children 可能会用信号淹没 parent,那么最好使用实时信号生成函数 (sigqueue()
) 而不是 kill()
。不同之处在于,使用 sigqueue()
,所有信号都会排队,并且不需要 SA_NODEFER
来避免丢弃信号,而其他一些信号处理程序是 运行ning:
https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/V2_chap02.html#tag_15_04_02
最终结论:代码应该完全重写。