如何在 C++ 中使用信号以及它们如何反应?
How to use signals in C++ and How they react?
我正在尝试了解有关信号的所有交互,但我发现其中有一个我无法理解的有趣交互。
这是程序的摘要,我指示用 grandchild 执行 execvp,而 child 需要等待 grandchild 完成。它 运行 在没有任何信号交互的情况下是正确的。
void say_Hi(int num) { printf("Finished\n"); }
int main() {
int i = 2;
char *command1[] = {"sleep", "5", NULL};
char *command2[] = {"sleep", "10", NULL};
signal(SIGCHLD, SIG_IGN);
signal(SIGUSR1, say_Hi);
while(i > 0) {
pid_t pid = fork();
if (pid == 0) {
pid_t pidChild = fork();
if (pidChild == 0) {
if (i == 2) {
execvp(command1[0], command1);
} else {
execvp(command2[0], command2);
}
} else if (pidChild > 0) {
waitpid(pidChild, 0, 0);
// kill(pid, SIGUSR1);
printf("pid finished: %d\n", pidChild);
exit(EXIT_FAILURE);
}
exit(EXIT_FAILURE);
} else {
//parent immediately goes to next loop
i--;
}
}
cin >> i; //just for me to pause and observate answers above
return 0;
}
如上图, kill(pid, SIGUSR1);
被注释,程序运行正确
输出:
pid finished: 638532 //after 5 sec
pid finished: 638533 //after 10 sec
然而,当它被取消注释时。输出变为:
Finished
pid finished: 638610 //after 5 sec
Finished
Finished
Finished
Finished
pid finished: 638611 //after 5 sec too, why?
Finished
我想问:
整个程序在5秒后一下子结束,一共打印了6个“Finished”。为什么会这样?
有没有办法让我修改它,使 say_Hi 在正确的时间间隔内总共只运行两次 运行?
如果我的代码看起来愚蠢或笨重,请原谅我,我是编程新手。感谢对我的代码和帮助的任何评论!
void say_Hi(int num) { printf("Finished\n"); }
printf
不能在信号处理程序中调用。 None 的 C 或 C++ 库函数(除了少数例外)可以在信号处理程序中调用。您甚至不能从信号处理程序中分配或删除任何内存(使用 C 或 C++ 库),除非使用 low-level OS 调用,如 brk()
或 sbrk()
.这是因为一个非常简单的原因:none 的 C 或 C++ 库函数是 signal-safe(很少 例外)。只能从信号处理程序调用函数调用 that are explicitly designated 作为“signal-safe”。 None 的 C 或 C++ 库函数或 类(除了少数例外)是 signal-safe。结束。
唯一可以从信号处理程序调用的是 low-level 操作系统调用,如 read()
和 write()
,它们直接在文件句柄上运行。根据定义,它们是 signal-safe.
由于这个简单的原因,显示的代码在涉及信号时是未定义的行为。试图从这方面分析或弄清楚您的程序行为,例如为什么或为什么不看到此消息,是完全没有意义的。无法从逻辑上分析。这是未定义的行为。
答案:
kill(getpid(), SIG_USR1);
我正在尝试了解有关信号的所有交互,但我发现其中有一个我无法理解的有趣交互。
这是程序的摘要,我指示用 grandchild 执行 execvp,而 child 需要等待 grandchild 完成。它 运行 在没有任何信号交互的情况下是正确的。
void say_Hi(int num) { printf("Finished\n"); }
int main() {
int i = 2;
char *command1[] = {"sleep", "5", NULL};
char *command2[] = {"sleep", "10", NULL};
signal(SIGCHLD, SIG_IGN);
signal(SIGUSR1, say_Hi);
while(i > 0) {
pid_t pid = fork();
if (pid == 0) {
pid_t pidChild = fork();
if (pidChild == 0) {
if (i == 2) {
execvp(command1[0], command1);
} else {
execvp(command2[0], command2);
}
} else if (pidChild > 0) {
waitpid(pidChild, 0, 0);
// kill(pid, SIGUSR1);
printf("pid finished: %d\n", pidChild);
exit(EXIT_FAILURE);
}
exit(EXIT_FAILURE);
} else {
//parent immediately goes to next loop
i--;
}
}
cin >> i; //just for me to pause and observate answers above
return 0;
}
如上图, kill(pid, SIGUSR1);
被注释,程序运行正确
输出:
pid finished: 638532 //after 5 sec
pid finished: 638533 //after 10 sec
然而,当它被取消注释时。输出变为:
Finished
pid finished: 638610 //after 5 sec
Finished
Finished
Finished
Finished
pid finished: 638611 //after 5 sec too, why?
Finished
我想问:
整个程序在5秒后一下子结束,一共打印了6个“Finished”。为什么会这样?
有没有办法让我修改它,使 say_Hi 在正确的时间间隔内总共只运行两次 运行?
如果我的代码看起来愚蠢或笨重,请原谅我,我是编程新手。感谢对我的代码和帮助的任何评论!
void say_Hi(int num) { printf("Finished\n"); }
printf
不能在信号处理程序中调用。 None 的 C 或 C++ 库函数(除了少数例外)可以在信号处理程序中调用。您甚至不能从信号处理程序中分配或删除任何内存(使用 C 或 C++ 库),除非使用 low-level OS 调用,如 brk()
或 sbrk()
.这是因为一个非常简单的原因:none 的 C 或 C++ 库函数是 signal-safe(很少 例外)。只能从信号处理程序调用函数调用 that are explicitly designated 作为“signal-safe”。 None 的 C 或 C++ 库函数或 类(除了少数例外)是 signal-safe。结束。
唯一可以从信号处理程序调用的是 low-level 操作系统调用,如 read()
和 write()
,它们直接在文件句柄上运行。根据定义,它们是 signal-safe.
由于这个简单的原因,显示的代码在涉及信号时是未定义的行为。试图从这方面分析或弄清楚您的程序行为,例如为什么或为什么不看到此消息,是完全没有意义的。无法从逻辑上分析。这是未定义的行为。
答案:
kill(getpid(), SIG_USR1);