【发布时间】:2021-03-24 00:31:37
【问题描述】:
我正在尝试使用一个信号处理程序处理多个信号,预期结果是 ctrlc 退出子进程并退出父进程,而 ctrlz 每次按下 ctrlz 时都会打印一个随机数,但它似乎没有在处理第一个信号后工作。代码的另一部分是一个子进程,它循环直到调用 ctrl-c。 这是代码。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
#include <time.h>
#include <string.h>
int sig_ctrlc = 0;
int sig_ctrlz = 0;
//main signal handler to handle all signals
void SIGhandler(int sig) {
switch (sig) {
case SIGINT:
sig_ctrlc = SIGINT;
break;
case SIGTSTP:
sig_ctrlz = SIGTSTP;
break;
case SIGCHLD:
default: break;
}
}
int main() {
int fd[2]; //to store the two ends of the pipe
char get_inode[] = "ls -il STATUS.TXT";
FILE *fp;
FILE *log;
FILE *command;
time_t t;
time(&t);
int rv = 0;
log = fopen("file_log.txt", "w");
struct sigaction act;
memset (&act, 0, sizeof(struct sigaction));
act.sa_handler = SIGhandler;
//if pipe can't be created
if (pipe(fd) < 0) {
fprintf(log, "Pipe error");
}
int pid = fork();
switch(pid) {
case -1:
fprintf(stderr, "fork failed\n");
exit(1);
case 0:
/*child process */
// maps STDOUT to the writing end of the pipe
// if (dup2(fd[1], STDOUT_FILENO) == -1) {
// fprintf(log, "error in mapping stdout to the writing pipe\n");
// }
act.sa_flags = SA_RESTART;
sigemptyset(&act.sa_mask);
sigaction(SIGINT, &act, NULL);
sigaction(SIGTSTP, &act, NULL);
for (size_t i = 1;; i++) {
/* code */
printf(" running in child\n");
sleep(1);
if (sig_ctrlc != 0) {
printf("ctrlc handled\n");
printf("exiting...\n");
sig_ctrlc = 0;
break;
}
if (sig_ctrlz != 0) {
printf("ctlrz handled.\n");
/* random generator, the problem with this is it runs with time if ctrlz
is handled within a second it returns the same number
*/
srand(time(0));
int rand_num;
rand_num = rand() % (50 - 10 + 1) + 10;
printf("random number: %d\n", rand_num);
sig_ctrlz = 0;
sigaction(SIGINT, &act, NULL);
sigaction(SIGTSTP, &act, NULL);
}
}
default:
/* parent process */
close(fd[1]);
//maps STDIN to the reading end of the pipe
// if (dup2(fd[0], STDIN_FILENO) < 0) {
// fprintf(log, "can't redirect");
// exit(1);
// }
// //checks for fopen not working and writes to STATUS.TXT with a redirect
// if ((fp = freopen("STATUS.TXT", "w", stdout)) != NULL) {
// printf("start time of program: %s\n", ctime(&t));
// printf("Parent process ID: %d\n", getppid());
// printf("Child process ID: %d\n", getpid());
//
// //gets inode information sends the command to and receives the info from the terminal
// command = popen(get_inode, "w");
// fprintf(command, "STATUS.TXT");
// fclose(command);
//
//// map STDOUT to the status file
// if(freopen("STATUS.TXT", "a+ ", stdout) == NULL) {
// fp = fopen("file_log.txt","w");
// fprintf(log, "can't map STATUS.TXT to stdout\n");
// exit(1);
// }
//
printf("parent has started\n");
wait(NULL);
time(&t);
printf("PARENT: My child's termination status is: %d at: %s\n", WEXITSTATUS(rv), ctime(&t));
// fprintf(fp, "PARENT: My child's termination status is: %d at: %s\n", WEXITSTATUS(rv), ctime(&t));
// fclose(fp);
// fclose(log);
sigaction(SIGINT, &act, NULL);
for (size_t i = 1;; i++) {
/* code */
printf("PARENT: in parent function\n");
sleep(1);
if (sig_ctrlc != 0)
exit(0);
}
}
return 0;
}
【问题讨论】:
-
我认为您在
case 0:的末尾缺少break;或exit()。就目前而言,在处理信号并跳出循环后,子进程陷入default:案例并运行为父进程准备的代码。 -
如果这不是问题,请更清楚地解释您的问题。运行程序后你输入了什么,你看到了什么输出,你期待什么输出?
-
您应该检查来自
wait()的返回值,以确保您获得了正确尸体的详细信息。看起来您应该调用int corpse = wait(&rv);以便获得孩子的退出状态,而不是无条件地看到0。 -
“不起作用”是什么意思?它适用于第一个
Ctrl-Z,但不适用于后面的Ctrl-Z? -- 你可能想阅读更多关于信号的信息。尤其是触发handler时,是否恢复默认为implementation-defined。 -
@thebusybee 处理完任何信号后,包括处理过的信号在内的所有信号都无法再次处理(如果按下 ctrlc 或 ctrlz 则不会执行任何操作)
标签: c signals signal-handling