父进程循环随机发送SIGUSR1/SIGUSR2给子进程失败问题排查
问题分析与修复方案
核心问题点
- PID传递错误:父进程调用
parent_func(0),kill(0, 信号)会向当前进程组所有进程发信号,后续循环无法精准定位子进程。应传递fork返回的子进程PID。 - 重复设置信号处理:子进程循环内反复调用
signal()重置信号处理,冗余且可能引发异常。信号处理只需初始化一次,推荐用sigaction替代signal(行为更稳定可移植)。 - 随机数种子重复初始化:每次调用
parent_func都执行srand(time(NULL)),短时间内time(NULL)返回相同值,导致随机数重复,信号选择失去随机性。 - 未实现信号写入文件逻辑:原需求要求子进程接收信号后写入文件,但当前信号处理函数仅打印信息,未完成文件写入。
修复后的完整代码
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <time.h> #include <sys/time.h> #include <sys/types.h> // 声明日志函数 void log_signal(int sig); void handler_sigusr1(int sig) { if (sig == SIGUSR1) { puts("child received SIGUSR1"); log_signal(SIGUSR1); } } void handler_sigusr2(int sig) { if (sig == SIGUSR2) { puts("child received SIGUSR2"); log_signal(SIGUSR2); } } void parent_send_signal(int child_pid) { int rnd = rand(); int target_sig = (rnd & 1) ? SIGUSR2 : SIGUSR1; struct timeval t; gettimeofday(&t, NULL); unsigned long time = 1000000 * t.tv_sec + t.tv_usec; printf("signal to send: %d\n", target_sig); printf("current timestamp: %ld\n", time); kill(child_pid, target_sig); } void log_signal(int sig) { FILE *file = fopen("received_signal.txt", "a"); if (file == NULL) { perror("fopen failed"); return; } struct timeval t; gettimeofday(&t, NULL); unsigned long time = 1000000 * t.tv_sec + t.tv_usec; fprintf(file, "%s\t%ld\t%d\n", sig == SIGUSR1 ? "SIGUSR1" : "SIGUSR2", time, getpid()); fclose(file); } int main(int argc, char* argv[], char *envp[]) { // 初始化日志文件表头 FILE *file = fopen("received_signal.txt", "w"); if (file == NULL) { perror("fopen failed"); exit(EXIT_FAILURE); } fprintf(file, "%s\t%s\t%s\n", "Signal Type", "Signal Time", "Process ID"); fclose(file); pid_t pid = fork(); if (pid == 0) { // 子进程:接收信号 struct sigaction sact1, sact2; // 配置SIGUSR1处理 sact1.sa_handler = handler_sigusr1; sigemptyset(&sact1.sa_mask); sact1.sa_flags = 0; sigaction(SIGUSR1, &sact1, NULL); // 配置SIGUSR2处理 sact2.sa_handler = handler_sigusr2; sigemptyset(&sact2.sa_mask); sact2.sa_flags = 0; sigaction(SIGUSR2, &sact2, NULL); // 子进程进入休眠循环等待信号 while (1) { sleep(1); } } else { // 父进程:发送信号 srand(time(NULL)); // 仅初始化一次随机数种子 while (1) { printf("parent loop running\n"); parent_send_signal(pid); usleep(((rand() % 5) + 1) * 10000); // 随机延迟0.01-0.05秒 } } return 0; }
修复说明
- PID传递修正:父进程调用
parent_send_signal(pid),将子进程PID传入,确保kill精准发送信号到目标进程。 - 信号处理优化:子进程使用
sigaction一次性配置信号处理逻辑,无需循环重置,行为更稳定。 - 随机数种子优化:父进程在循环外仅初始化一次
srand,避免短时间内重复种子导致随机数相同。 - 文件写入实现:补充
log_signal函数,以追加模式打开日志文件,写入信号类型、时间戳和进程ID,满足需求。
内容的提问来源于stack exchange,提问作者Mohammed Mohammed
相关产品推荐
相关产品推荐

