【发布时间】:2020-03-18 13:08:51
【问题描述】:
我们的任务是开发一个创建子进程的应用程序。然后父进程等待 3 秒(我们不允许在父进程中使用sleep)并发送一个SIGUSR2 信号,然后是一个SIGUSR1 信号。之后,父母会定期(3 秒)向孩子发送SIGUSR1 信号,直到它终止。在子终止时,它会打印 Parent done 并退出。我们应该使用alarm() 和pause() 来实现这种行为。
子进程应该阻塞信号SIGUSR2 13 秒。收到SIGUSR1 后,它应该打印Received SIGUSR1。收到SIGUSR2 后,它会打印Child done 并退出。我的实现方法如下:
请注意:SIGUSR2 信号只发送一次,直到现在我还没有实现,每次都与SIGUSR1 信号一起发送。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <stdarg.h>
static pid_t chld;
void init_signal(struct sigaction* action, void (*handler)(int));
void init_sigset(sigset_t* set, int signum);
void bind_signal(struct sigaction* action, int n, ...);
void par_signal(int signum);
void chld_signal(int signum);
int main(){
chld = fork();
struct sigaction action;
if (chld == -1){
fprintf(stderr, "Failed to create child process.\n");
return EXIT_FAILURE;
} else if (chld == 0){
init_signal(&action, &chld_signal);
bind_signal(&action, 3, SIGUSR1, SIGUSR2, SIGALRM);
sigset_t sig;
init_sigset(&sig, SIGUSR2);
sigprocmask(SIG_BLOCK, &sig, NULL);
alarm(13);
pause();
}
init_signal(&action, &par_signal);
bind_signal(&action, 2, SIGALRM, SIGCHLD);
alarm(3);
pause();
}
void init_signal(struct sigaction* action, void (*handler)(int)){
action->sa_flags = 0;
action->sa_handler = handler;
sigemptyset(&action->sa_mask);
}
void init_sigset(sigset_t* set, int signum){
sigemptyset(set);
sigaddset(set, signum);
}
void bind_signal(struct sigaction* action, int n, ...){
va_list args;
va_start(args, n);
for (int i = 0; i < n; i++){
int signum = va_arg(args, int);
sigaction(signum, action, NULL);
}
va_end(args);
}
void par_signal(int signum){
if (signum == SIGALRM){
kill(chld, SIGUSR2);
kill(chld, SIGUSR1);
alarm(3);
pause();
} else if (signum == SIGCHLD){
printf("Parent done\n");
exit(EXIT_SUCCESS);
}
}
void chld_signal(int signum){
if (signum == SIGALRM){
sigset_t sig;
init_sigset(&sig, SIGUSR2);
sigprocmask(SIG_UNBLOCK, &sig, NULL);
pause();
} else if (signum == SIGUSR1){
printf("Received SIGUSR1\n");
pause();
} else if (signum == SIGUSR2){
printf("Child done\n");
exit(EXIT_SUCCESS);
}
}
它的工作原理是,只有父进程的第一个信号被子进程接收。我认为这与我对pause 和alarm 的使用有关。你知道我做错了什么吗?
可以找到练习任务表的链接here(任务 3)。
【问题讨论】:
-
我很好奇,你是说:“之后,父母会定期(3 秒)向孩子发送 SIGUSR1 信号,直到它终止” - 然后你说:“收到 SIGUSR2 后,[子进程] 打印 Child done 并退出。” - 如果父进程在开始时只发送一次 SIGUSR2,然后继续发送 SIGUSR1,这怎么可能?父母是否应该在任意秒数后的某个时间发送 SIGUSR2?
-
根据我们的任务表,
SIGUSR2信号只能在 3 秒后发送一次。孩子阻止了它,因此它不会立即收到,而是在 13 秒后才收到。我暂时没有正确实现这一点,因为父母还不断向孩子发送SIGUSR2(这应该没有任何区别,因为它被阻止了)。 -
@ThomasThaler 您应该edit 您的问题并在那里添加所有说明或要求的信息,而不是编写 cmets。我建议信号处理程序不应该做的不仅仅是设置
volatile sig_atomic_t类型的变量。在任何情况下,信号处理程序都不得调用任何非异步信号安全的函数。printf不是。见man signal-safety。从信号处理程序调用pause可能会有问题。触发信号处理程序的信号通常会被阻塞,直到您从信号处理程序返回。 -
@Bodo 我添加了练习任务表的链接以及我在 cmets 中提供的信息