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

C语言实现生产者消费者问题时如何优雅退出consumer避免core dumped

问题根因

你遇到的Quit (core dumped)、killed语句不输出的问题,是代码里存在几个严重的逻辑错误导致的:

  1. 共享内存申请大小错误:mmap时传入的是sizeof(shared),shared是指针类型,64位系统下仅占8字节,远小于struct requiredmemory的实际大小,后续访问共享内存时会出现越界,直接触发段错误。
  2. 消费者PID存储错误:fork消费者的循环里,父进程错误把消费者PID存入了producers数组,consumers数组全程是垃圾值。后续父进程杀消费者时,实际是向随机PID发信号,大概率会杀到无效进程甚至父进程自身,导致父进程异常退出,自然不会打印killed相关日志。
  3. 跳转标签错误:fork消费者出错时错误跳转到了生产者错误处理的标签,逻辑混乱。
  4. 信号处理的安全问题:SIGQUIT默认行为是生成核心转储,且signal函数在不同系统下的行为不稳定,同时sem_wait被信号打断时没有做错误处理。

修复方案

1. 修复共享内存申请

把mmap的大小改为结构体的实际大小:

struct requiredmemory *shared = mmap(NULL, sizeof(struct requiredmemory), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);

2. 修复消费者PID存储逻辑

修改fork消费者的循环,将PID正确存入consumers数组,同时修正跳转标签:

for (c = 0; c < C; c++)
{
    pid_t pid = fork();
    if (pid < 0)
        goto error_forking_c; // 修正跳转标签
    else if (pid)
    {
        consumers[c] = pid; // 正确存入消费者数组
    }
    else
    {
        id = c;
        goto consumer;
    }
}

3. 优化消费者退出逻辑(更干净的实现,无需发信号)

不用信号杀消费者的方式,改为共享标志位主动退出,彻底避免信号带来的异常:

  • 在struct requiredmemory里新增退出标志:
    struct requiredmemory
    {
        sem_t f, e, m;
        int total, start, count;
        int producer_exit; // 新增:所有生产者是否已退出
        unsigned char circular_buffer[50];
    };
    
  • 父进程等待所有生产者退出后,设置标志位,并唤醒所有阻塞的消费者:
    while (p--)
        wait(NULL);
    shared->producer_exit = 1; // 标记生产者全部退出
    for(int i=0; i<C; i++) 
        sem_post(full); // 唤醒所有阻塞在sem_wait(full)的消费者
    // 等待所有消费者主动退出
    for(int i=0; i<C; i++)
        waitpid(consumers[i], NULL, 0);
    
  • 消费者循环里增加退出判断,删除原有信号处理相关代码:
    consumer:
    {
        count = 0;
        while (1)
        {
            unsigned char num = 0;
            sem_wait(full);
            sem_wait(mutex);
            // 生产者已退出且缓冲区为空,直接退出
            if(shared->producer_exit && shared->count == 0) {
                sem_post(mutex);
                sem_post(empty);
                break;
            }
            num = shared->circular_buffer[shared->start];
            shared->start = (shared->start + 1) % BUFFER_LEN;
            shared->count -= 1;
            shared->total += num;
            sem_post(mutex);
            sem_post(empty);
            count++;
            localtotal += num;
        }
        printf("Consumer %d : consumed %d items totalling to %d\n", id, count, localtotal);
        fflush(stdout);
        return 0;
    }
    

额外优化点

  • 生产者随机数种子修改为srand(time(NULL) ^ getpid()),避免多个生产者同时启动时种子相同,生成重复的随机数。
  • 所有printf后加fflush(stdout),避免多进程下输出缓冲区混乱。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 14:09:04