父进程SIGCONT信号异常:唤醒后无法读取输入及执行后续代码
父进程被SIGCONT唤醒后无法读取输入的问题排查与解决
问题背景
需求:让父进程暂停,直到子进程发送SIGCONT唤醒信号后,再继续执行剩余代码。
问题:编写的C语言代码中,父进程被唤醒后仅输出提示语句,无法读取字符串输入,也不会执行最后的printf语句。
问题代码
#include <stdio.h> #include <stdlib.h> // EXIT_FAILURE #include <unistd.h> // for fork #include<sys/wait.h> // for wait #include <signal.h> // for sa_handler #define SIZE 100 // maximum characters allowed in the chat int main(){ char ptr[100] = "\0"; pid_t pid = fork(); // fork a processes if(pid < 0){ perror("Fork #1 failed..\n"); exit(EXIT_FAILURE); } else if (pid > 0){ // Parent Process raise(SIGSTOP); printf("Please enter message...\n"); fgets(ptr, SIZE, stdin); printf("Parent Message: \033[0;31m%s\n", ptr); // RED color font } else { // Child A sleep(2); kill(getppid(), SIGCONT); exit(0); } wait(NULL); return 0; }
原因分析
- SIGSTOP导致父进程脱离终端前台进程组:程序启动时父进程处于终端前台进程组,调用
raise(SIGSTOP)后父进程被暂停,此时shell自动接管前台进程组。子进程发送SIGCONT唤醒父进程后,父进程在后台运行,而终端输入仅会发送给前台进程组的进程,因此fgets会一直阻塞,无法读取用户输入,后续的printf语句自然也无法执行。 wait(NULL)位于main函数末尾,父进程需要执行完分支内的代码才能到达这一步,但由于fgets阻塞,父进程无法走到该逻辑。
解决建议
方案1:使用自定义信号替代SIGSTOP/SIGCONT
父进程通过pause()阻塞等待子进程发送自定义信号,这种方式不会让父进程脱离前台进程组,避免终端输入问题:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <signal.h> #define SIZE 100 // 自定义信号处理函数,仅用于唤醒pause void sig_usr_handler(int sig) {} int main(){ char ptr[SIZE] = "\0"; struct sigaction sa; // 注册SIGUSR1信号的处理函数 sa.sa_handler = sig_usr_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGUSR1, &sa, NULL); pid_t pid = fork(); if(pid < 0){ perror("Fork failed"); exit(EXIT_FAILURE); } else if (pid > 0){ // 父进程 pause(); // 阻塞等待子进程的信号 printf("Please enter message...\n"); fgets(ptr, SIZE, stdin); // 输出后恢复终端默认颜色 printf("Parent Message: \033[0;31m%s\033[0m\n", ptr); wait(NULL); } else { // 子进程 sleep(2); kill(getppid(), SIGUSR1); // 发送自定义信号唤醒父进程 exit(0); } return 0; }
方案2:唤醒后重新获取前台进程组控制权
如果坚持使用SIGSTOP/SIGCONT,可以在父进程被唤醒后,调用tcsetpgrp()将自己重新设置为终端前台进程组:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <signal.h> #include <termios.h> #define SIZE 100 int main(){ char ptr[SIZE] = "\0"; int terminal_fd = STDIN_FILENO; pid_t parent_pgid = getpgrp(); // 获取父进程的进程组ID pid_t pid = fork(); if(pid < 0){ perror("Fork failed"); exit(EXIT_FAILURE); } else if (pid > 0){ // 父进程 raise(SIGSTOP); // 重新获取终端前台进程组控制权 if(tcsetpgrp(terminal_fd, parent_pgid) == -1){ perror("Failed to regain terminal foreground control"); exit(EXIT_FAILURE); } printf("Please enter message...\n"); fgets(ptr, SIZE, stdin); printf("Parent Message: \033[0;31m%s\033[0m\n", ptr); wait(NULL); } else { // 子进程 sleep(2); kill(getppid(), SIGCONT); exit(0); } return 0; }
内容的提问来源于stack exchange,提问作者Joy
相关产品推荐
相关产品推荐

