fork()实现信号通信与独立闹钟:输出异常问题咨询
信号通信问题排查(分离闹钟与父子进程信号)
问题描述
执行「分离闹钟与父子进程信号通信」任务时,使用fork()编写的代码出现两处异常:
- 在
user2函数中用getpid()获取子进程PID,预期为22732,但实际输出22731; - 输出末尾出现未编写打印逻辑的「User defined signal 2」消息,来源不明。
原代码
#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <sys/wait.h> void child_handler (int signum){ printf("Child (PID=%d) alarm went off\n", getpid()); // send signal to parent kill( getppid(), SIGUSR1 ); exit(EXIT_SUCCESS); } void parent_handler (int signum){ printf("Parent (PID=%d) received SIGUSR1 from child after child's alarm\n", getppid()); } void user2 (int signum){ printf("Parent (PID=%d) alarm went off\n", getppid()); printf("Parent (PID=%d) sending SIGUSR2 to my child %d\n", getppid(), getpid()); kill( getpid(), SIGUSR2 ); exit(EXIT_SUCCESS); } int main(){ int pid; int status; // 1.The parent process forks a child process. pid = fork(); if (pid == 0){ // child process printf("Child (PID=%d) setting my alarm to 3 and then wait via pause()\n", getpid()); signal(SIGALRM, child_handler); alarm(3); pause(); // 2. The child process sets an alarm for 3 seconds and waits for the SIGALRM signal. } else if (pid > 0){ // parent process printf("Parent (PID=%d) preparing waiting for SIGUSR1 via pause()\n", getppid()); signal(SIGUSR1, parent_handler); pause(); // 5.The parent process sets an alarm for 5 seconds and waits for its SIGALRM signal. printf("Parent (PID=%d) Setting alarm for 5 seconds and wait via pause()\n", getppid()); signal(SIGALRM, user2); alarm(5); pause(); //waitpid(pid, &status, 0); } else { // error perror("Failed to fork child process.\n"); exit(EXIT_FAILURE); } return 0; }
原运行输出
Parent (PID=15925) preparing waiting for SIGUSR1 via pause() Child (PID=22732) setting my alarm to 3 and then wait via pause() Child (PID=22732) alarm went off Parent (PID=15925) received SIGUSR1 from child after child's alarm Parent (PID=15925) Setting alarm for 5 seconds and wait via pause() Parent (PID=15925) alarm went off Parent (PID=15925) sending SIGUSR2 to my child 22731 User defined signal 2
问题分析与修复
1. 子进程PID获取错误
- 原因:
user2是父进程的信号处理函数,在父进程中调用getpid()返回的是父进程自身的PID,而非子进程PID。子进程PID存储在main函数的局部变量pid中,user2无法访问该变量,导致输出错误;此外原代码中父进程打印自身PID时误用getppid()(返回父进程的父进程,即Shell进程的PID),应改为getpid()。 - 修复:将子进程PID存储为全局变量,让
user2能直接获取;同时修正父进程打印自身PID的调用。
2. 「User defined signal 2」消息来源
- 原因:
user2函数中kill(getpid(), SIGUSR2)是给父进程自身发送SIGUSR2信号,但未给父进程设置该信号的自定义处理函数,系统触发默认逻辑,打印该消息并终止进程。另外子进程在3秒后已退出,即使正确发送信号也会报错,但当前核心错误是信号发送对象错误。 - 修复:将
kill(getpid(), SIGUSR2)改为kill(child_pid, SIGUSR2),给子进程发送信号;同时添加错误处理,避免子进程已退出时的报错。
修复后代码
#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <sys/wait.h> // 全局变量存储子进程PID,供user2函数访问 pid_t child_pid; void child_handler (int signum){ printf("Child (PID=%d) alarm went off\n", getpid()); // 向父进程发送SIGUSR1 kill(getppid(), SIGUSR1); exit(EXIT_SUCCESS); } void parent_handler (int signum){ printf("Parent (PID=%d) received SIGUSR1 from child after child's alarm\n", getpid()); } void user2 (int signum){ printf("Parent (PID=%d) alarm went off\n", getpid()); printf("Parent (PID=%d) sending SIGUSR2 to my child %d\n", getpid(), child_pid); // 向子进程发送SIGUSR2,添加错误处理 if (kill(child_pid, SIGUSR2) == -1) { perror("Failed to send SIGUSR2 to child"); } exit(EXIT_SUCCESS); } int main(){ int status; // 父进程创建子进程 child_pid = fork(); if (child_pid == 0){ // 子进程逻辑 printf("Child (PID=%d) setting my alarm to 3 and then wait via pause()\n", getpid()); signal(SIGALRM, child_handler); alarm(3); pause(); } else if (child_pid > 0){ // 父进程逻辑 printf("Parent (PID=%d) preparing waiting for SIGUSR1 via pause()\n", getpid()); signal(SIGUSR1, parent_handler); pause(); // 设置5秒闹钟并等待 printf("Parent (PID=%d) Setting alarm for 5 seconds and wait via pause()\n", getpid()); signal(SIGALRM, user2); alarm(5); pause(); // 等待子进程退出,避免僵尸进程 waitpid(child_pid, &status, 0); } else { // fork失败处理 perror("Failed to fork child process.\n"); exit(EXIT_FAILURE); } return 0; }
内容的提问来源于stack exchange,提问作者tof
相关产品推荐
相关产品推荐

