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

关于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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:34:22