父子进程信号通信故障:无法进入子进程分支及SIGUSR1信号失效
问题排查:父子进程信号通信失败+子进程未正常启动
你的代码存在三个核心问题,直接导致了子进程无法启动、信号无效的现象:
1. FIFO阻塞导致父进程卡在open步骤,根本未执行fork
FIFO的O_RDONLY打开模式是阻塞模式,如果没有进程以O_WRONLY打开写端,调用open的进程会一直挂起。你的父进程在创建子进程之前就执行了canal = open("./canal",O_RDONLY);,这时候如果客户端还未启动,父进程会直接卡在这一步,完全到不了创建子进程的代码逻辑。
修复方案:将打开FIFO的操作移到fork之后的父进程分支中,避免阻塞子进程创建流程。
2. 子进程分支代码执行顺序完全颠倒
在子进程分支里,你先调用了octal(pipe_fd[0]);,这个函数内部是while(1)死循环+pause(),导致后续的signal(SIGUSR1,octal);根本没有执行机会。信号处理函数都没注册,发送SIGUSR1自然不会有任何反应。
修复方案:先注册信号处理函数,再进入等待信号的循环。
3. 信号处理函数签名不匹配
signal()要求的处理函数签名是void handler(int signal_number),但你的octal和hexa函数参数是int fd,这会导致信号触发时调用栈混乱,行为完全未定义。
修复方案:将文件描述符改为全局变量,或者使用sigaction传递参数(这里采用全局变量的简单实现)。
修复后的calculator.c代码
#include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <string.h> #include <sys/file.h> #include <signal.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <sys/wait.h> // 全局变量存储子进程需要的管道文件描述符 int global_fd; void octal(int sig){ int valor; read(global_fd,&valor,sizeof(int)); printf("%o\n",valor); } void hexa(int sig){ int valor; read(global_fd,&valor,sizeof(int)); printf("%X\n",valor); } int main(){ int canal,pipe_fd[2],octal_pid,hexa_pid; unlink("canal"); if(mkfifo("./canal", 00660)!=0){ perror("Error al crear la pipe"); exit(EXIT_FAILURE); } pipe(pipe_fd); octal_pid = fork(); if(octal_pid == -1){ perror("Error al crear el proceso octal"); exit(EXIT_FAILURE); } else if(octal_pid == 0){ close(pipe_fd[1]); global_fd = pipe_fd[0]; // 先注册信号处理函数,再进入等待循环 signal(SIGUSR1,octal); while(1){ pause(); } } else { hexa_pid = fork(); if(hexa_pid == -1){ perror("Error al crear el proceso hexadecimal"); kill(octal_pid, SIGTERM); exit(EXIT_FAILURE); } else if(hexa_pid == 0){ close(pipe_fd[1]); global_fd = pipe_fd[0]; signal(SIGUSR1,hexa); while(1){ pause(); } } else { close(pipe_fd[0]); // 父进程最后打开FIFO读端,避免阻塞子进程创建 canal = open("./canal",O_RDONLY); if(canal < 0){ perror("Error al obrir la pipe"); kill(octal_pid, SIGTERM); kill(hexa_pid, SIGTERM); exit(EXIT_FAILURE); } while(1){ char c; int valor; ssize_t read_ret = read(canal,&c,sizeof(char)); if(read_ret <=0) break; read_ret = read(canal,&valor,sizeof(int)); if(read_ret <=0) break; if(c == 'o'){ printf("Calculant en octal ... \n"); write(pipe_fd[1], &valor, sizeof(int)); kill(octal_pid,SIGUSR1); } else if(c == 'h'){ printf("Calculant en hexadecimal ... \n"); write(pipe_fd[1], &valor, sizeof(int)); kill(hexa_pid,SIGUSR1); } else if( c == 'x'){ printf("Sortint...\n"); kill(octal_pid, SIGTERM); kill(hexa_pid, SIGTERM); break; } } close(canal); close(pipe_fd[1]); waitpid(octal_pid, NULL, 0); waitpid(hexa_pid, NULL, 0); } } unlink("canal"); // 退出前清理FIFO文件 return 0; }
修复后的client.c小调整(优化输入处理)
#include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <string.h> #include <sys/file.h> #include <signal.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <sys/wait.h> int fd, valor; char operacio; int llegir_numero() { char buff [10]; int llegits; llegits=read(0, buff, 10); if(llegits <=0) return 0; // 替换输入中的换行/回车符为结束符 for(int i=0;i<llegits;i++){ if(buff[i] == '\n' || buff[i] == '\r'){ buff[i] = '\0'; break; } } return(atoi(buff)); } int main(){ fd = open("./canal",O_WRONLY); if(fd < 0){ perror("La pipe no s'ha obert correctament"); exit(EXIT_FAILURE); } do{ printf("Introdueix 'o' o 'h', x per acabar\n"); // 清理输入缓冲区残留字符 while(getchar() != '\n'); scanf("%c",&operacio); if(operacio == 'o' || operacio == 'h'){ printf("Introdueix un valor enter positiu:\n"); valor = llegir_numero(); write(fd,&operacio,sizeof(char)); write(fd,&valor,sizeof(int)); } else if(operacio != 'x'){ printf("Lletra incorrecte.\n"); } } while(operacio != 'x'); close(fd); return 0; }
内容的提问来源于stack exchange,提问作者loststudent
相关产品推荐
相关产品推荐

