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

使用进程实现生产者-消费者模型时遇SIGUSR1错误求助

分析你的生产者-消费者程序错误及修复方案

首先,你遇到的User defined signal 1: 30错误(对应SIGUSR1信号异常),根源在于代码里的多个逻辑和语法问题,我帮你逐一拆解并修正:

主要问题点

  • 信号处理函数不符合标准原型:
    系统调用signal()要求信号处理函数必须接收一个int类型的参数(表示触发的信号编号),但你的producer()和consumer()函数没有参数,这会导致信号触发时栈帧异常,直接引发未定义行为,这是你看到信号错误的核心原因之一。

  • 进程间PID传递错误:
    全局变量child和parent在fork后是父子进程各自独立的副本:

    • 父进程里的child从未被正确赋值(子进程里的child = getpid()只在子进程生效,父进程看不到),导致父进程执行kill(child, SIGUSR1)时,实际是向PID为0的进程组发信号,而非目标子进程。
    • 子进程里的parent变量也未被正确初始化(父进程设置parent=getpid()的分支子进程不会执行),导致子进程执行kill(parent, SIGUSR2)同样是无效操作。
  • 循环逻辑错误:
    你把fork()放在for循环外,但父子进程都会进入同一个for循环,这会导致双方各自独立执行10次循环,完全不符合"生产者创建文件→发信号→消费者删除→发信号→重复"的交替逻辑。

  • 初始文件创建多余且可能引发冲突:
    程序开头的system("touch file")没必要,而且可能导致消费者第一次删除时文件已存在,但后续逻辑会重复创建,反而容易引发混乱。

修正后的代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

// 全局变量存储父子进程PID,确保双方都能拿到正确值
pid_t child_pid;
pid_t parent_pid;

// 符合标准的信号处理函数,接收信号编号参数
void producer_handler(int signo) {
    // 生产者创建文件
    system("touch file");
    printf("Producer: File was created.\n");
    // 通知消费者可以删除
    kill(child_pid, SIGUSR1);
}

void consumer_handler(int signo) {
    // 消费者删除文件
    system("rm file");
    printf("Consumer: File was deleted.\n");
    // 通知生产者可以再次创建
    kill(parent_pid, SIGUSR2);
}

int main(void) {
    parent_pid = getpid();
    pid_t pid = fork();

    if (pid < 0) {
        perror("fork() failed");
        return EXIT_FAILURE;
    } else if (pid == 0) {
        // 子进程(消费者)逻辑
        child_pid = getpid();
        // 注册SIGUSR1信号处理函数,触发时删除文件
        signal(SIGUSR1, consumer_handler);
        // 先通知父进程可以开始第一次创建
        kill(parent_pid, SIGUSR2);
        // 子进程进入等待信号的循环,执行10次
        for (int i = 0; i < 10; ++i) {
            pause();
        }
    } else {
        // 父进程(生产者)逻辑
        child_pid = pid; // 直接用fork返回的子进程PID,这是最可靠的方式
        // 注册SIGUSR2信号处理函数,触发时创建文件
        signal(SIGUSR2, producer_handler);
        // 父进程进入循环等待信号,执行10次创建
        for (int i = 0; i < 10; ++i) {
            pause();
        }
    }

    return EXIT_SUCCESS;
}

关键修正说明

  1. 信号处理函数标准化:
    给producer_handler和consumer_handler添加了int signo参数,符合signal()的要求,避免栈异常。

  2. 正确传递PID:
    父进程直接使用fork()返回的子进程PID赋值给child_pid,这是最可靠的方式;子进程则继承父进程在fork前就赋值好的parent_pid,确保双方都能正确找到目标进程。

  3. 修正循环与等待逻辑:
    父子进程各自进入自己的循环,通过pause()等待对方的信号,实现严格的交替执行:

    • 子进程启动后先主动发SIGUSR2给父进程,触发第一次文件创建
    • 父进程创建文件后发SIGUSR1给子进程,触发删除
    • 子进程删除后发SIGUSR2给父进程,如此循环10次
  4. 移除多余的初始文件创建:
    去掉了开头的touch file,让第一次创建由生产者逻辑触发,避免初始状态混乱。

运行说明

编译运行后,你会看到类似如下的交替输出:

Producer: File was created.
Consumer: File was deleted.
Producer: File was created.
Consumer: File was deleted.
...(重复10次)

这样就能实现你想要的"同一时间只能存在一个文件"的需求,也不会再出现信号相关的错误了。

内容的提问来源于stack exchange,提问作者sziko

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:59:56