我试图把注意力集中在信号上,所以我从运行GeeksforGeeks信号页面上的代码开始。在他们的页面上,它显示了父级和子级的输出,但是当我在CLion中运行时,我仅收到9/10次父级的输出,而子级则什么也不打印。孩子偶尔会打印一次,但我不知道为什么或如何使其始终打印。
https://www.geeksforgeeks.org/signals-c-set-2/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
void sighup();
void sigint();
void sigquit();
void main() {
int pid;
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
if (pid == 0) {
signal(SIGHUP, sighup);
signal(SIGINT, sigint);
signal(SIGQUIT, sigquit);
for(;;)
;
}
else {
printf("\nPARENT: sending SIGUP\n\n");
kill(pid, SIGHUP);
sleep(3);
printf("\nPARENT: sending SIGINT\n\n");
kill(pid, SIGINT);
sleep(3);
printf("\nPARENT: sending SIGQUIT\n\n");
kill(pid, SIGQUIT);
sleep(3);
}
void sighup() {
signal(SIGHUP, sighup);
printf("CHILD: I have received a SIGHUP\n");
}
void sigint() {
signal(SIGINT, sigint);
printf("CHILD: I have received a SIGINT\n");
}
void sigquit() {
printf("My parent has killed me");
exit(0);
}
答案 0 :(得分:0)
该代码充满了错误。您应该首先在编译器上启用警告。在GCC和clang上,这是通过传递标志-pedantic
和警告级别来完成的。我建议使用-Wall -Wextra -Werror
-这会给出相当严格的警告,而不会造成干扰。
如前所述,前两个错误是原型声明错误,并且main
函数签名错误。
第二个错误是您不能安全地在信号处理程序中调用printf
(您会在代码中遇到这种相对常见的情况,但这是错误的)。实际上,您可以在信号处理程序中安全执行的一系列操作受到严格限制-read the documentation carefully。
第三,代码重设处理程序的尝试被破坏了(至少没有必要)。 如果要重置处理程序,则需要传递SIG_DFL
作为第二个参数,而不是自定义回调。文档中也对此进行了解释。
最后,我们不能保证子进程中的代码先于父进程中的代码执行-特别是,不能保证将设置信号处理程序。在我的测试中,尽管父代码中有sleep
语句,但子代码最终不会被执行。这看似很奇怪,但这是完全合法的,需要预料到。
将这些部分放在一起可以为我们提供以下内容,您可能会注意到,这些内容比您尝试的无效代码要复杂得多。
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
static volatile sig_atomic_t child_signal;
static volatile sig_atomic_t setup_done = 0;
void child_signal_handler(int);
void parent_signal_handler(int);
int main() {
const int parent_pid = getpid();
int pid;
// Set up BEFORE calling `fork`
signal(SIGCHLD, parent_signal_handler);
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
if (pid == 0) {
signal(SIGHUP, child_signal_handler);
signal(SIGINT, child_signal_handler);
signal(SIGQUIT, child_signal_handler);
kill(parent_pid, SIGCHLD);
for (;;) {
if (child_signal != 0) {
switch ((int) child_signal) {
case SIGHUP:
fprintf(stderr, "CHILD: I have received a SIGHUP\n");
break;
case SIGINT:
fprintf(stderr, "CHILD: I have received a SIGINT\n");
break;
case SIGQUIT:
fprintf(stderr, "My parent has killed me");
exit(1);
}
child_signal = 0;
}
}
} else {
while (! setup_done) { sleep(1); }
printf("\nPARENT: sending SIGUP\n");
kill(pid, SIGHUP);
sleep(1);
printf("\nPARENT: sending SIGINT\n");
kill(pid, SIGINT);
sleep(1);
printf("\nPARENT: sending SIGQUIT\n");
kill(pid, SIGQUIT);
}
}
void child_signal_handler(int signo) {
child_signal = signo;
}
void parent_signal_handler(int signo) {
if (signo == SIGCHLD) setup_done = 1;
}