You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

父子进程信号通信故障:无法进入子进程分支及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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 11:47:57