关于signal、kill系统调用及信号处理程序的技术咨询
关于signal、kill系统调用与信号处理程序的问题
我整理了你提供的代码片段,先把补全后的代码展示出来(补充了缺失的语法部分和逻辑框架):
int figlio=-1; void gestore(int sig); // 声明信号处理函数 int main(int argc,char* argv[]) { int pid1,pid2,dormi,numero; float reciproco; signal(SIGUSR1,gestore); signal(SIGUSR2,gestore); numero=atoi(argv[1]); printf("Numero %d\n\n",numero); fflush(stdout); pid1=fork(); if(pid1>0) // 父进程分支 { pid2=fork(); if(numero%2 == 0) kill(pid1,SIGUSR1); else kill(pid2,SIGUSR2); wait(NULL); wait(NULL); } if(pid1 == 0) // 子进程1分支 { //sleep(1); printf("Sono il figlio 1, PID: %d\n", getpid()); fflush(stdout); // 此处应该等待信号触发处理逻辑 } // 缺失子进程2的分支逻辑(pid2 == 0的判断) } // 信号处理函数实现 void gestore(int sig) { if(sig == SIGUSR1) { printf("Figlio 1 ha catturato SIGUSR1\n"); fflush(stdout); } else if(sig == SIGUSR2) { printf("Figlio 2 ha catturato SIGUSR2\n"); fflush(stdout); } }
结合代码来看,我先指出几个核心的问题和优化点:
信号发送时机的坑:父进程在
fork()后立刻调用kill()发送信号,但此时子进程可能还没完成信号处理程序的注册(子进程复制父进程地址空间,但执行流独立,父进程的kill可能先于子进程的信号注册执行)。这会导致信号触发默认动作(SIGUSR1/2默认是终止进程),子进程直接退出,根本走不到后续的打印逻辑。你注释掉的sleep(1)是临时的缓解方式,但不够可靠,更好的做法是用同步机制(比如子进程发送就绪信号给父进程),确保子进程准备好后再发目标信号。代码完整性问题:
main()函数开头缺失大括号;没有实现gestore函数会导致编译报错;缺少子进程2的分支逻辑;figlio变量未被使用。输出缓冲的注意点:你代码里的
fflush(stdout)是必要的,因为printf是行缓冲,遇到换行才会自动刷新,但如果是重定向输出或者非终端场景,手动刷新才能确保内容及时输出,这部分做得没问题。进程等待的优化:两次
wait(NULL)可以等待所有子进程退出,但如果要精准等待特定PID的子进程,建议用waitpid()。
如果你的疑问是信号没被正确捕获、子进程没执行预期逻辑,那大概率是信号发送过早的问题。这里给你一个改进后的可靠版本:
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> #include <sys/wait.h> void gestore(int sig); int figli_pronti = 0; // 标记子进程就绪数量 int main(int argc,char* argv[]) { int pid1,pid2,numero; // 注册信号处理 signal(SIGUSR1,gestore); signal(SIGUSR2,gestore); signal(SIGCONT, gestore); // 用SIGCONT作为子进程就绪通知信号 // 参数校验 if(argc < 2) { fprintf(stderr, "用法: %s <整数>\n", argv[0]); exit(1); } numero=atoi(argv[1]); printf("Numero %d\n\n",numero); fflush(stdout); pid1=fork(); if(pid1>0) // 父进程 { pid2=fork(); // 等待两个子进程都就绪 while(figli_pronti < 2) { pause(); // 阻塞等待子进程的就绪信号 } // 发送目标信号 if(numero%2 == 0) kill(pid1,SIGUSR1); else kill(pid2,SIGUSR2); // 精准等待子进程退出 waitpid(pid1, NULL, 0); waitpid(pid2, NULL, 0); } else if(pid1 == 0) // 子进程1 { signal(SIGUSR1, gestore); // 显式注册(继承父进程的也可,这里做确认) printf("Sono il figlio 1, PID: %d\n", getpid()); fflush(stdout); figli_pronti++; kill(getppid(), SIGCONT); // 通知父进程自己就绪 pause(); // 阻塞等待信号 exit(0); } else if(pid2 == 0) // 子进程2 { signal(SIGUSR2, gestore); printf("Sono il figlio 2, PID: %d\n", getpid()); fflush(stdout); figli_pronti++; kill(getppid(), SIGCONT); // 通知父进程自己就绪 pause(); // 阻塞等待信号 exit(0); } return 0; } void gestore(int sig) { if(sig == SIGUSR1) { printf("Figlio 1 ha ricevuto SIGUSR1\n"); fflush(stdout); } else if(sig == SIGUSR2) { printf("Figlio 2 ha ricevuto SIGUSR2\n"); fflush(stdout); } else if(sig == SIGCONT) { // 父进程收到子进程就绪信号,仅唤醒pause,无需额外操作 } }
这个版本通过子进程发送SIGCONT信号通知父进程自己已准备好,父进程等待所有子进程就绪后再发送目标信号,彻底避免了信号丢失的问题。
内容的提问来源于stack exchange,提问作者FurioShow
相关产品推荐
相关产品推荐

