生产者完成生产后多消费者场景是否会出现进程永久阻塞问题?
问题验证结论
你描述的场景确实存在。
POSIX标准下计数信号量的sem_post()默认语义为单次仅唤醒至多1个阻塞在sem_wait()上的进程/线程:当缓冲区为空时items信号量计数为0,所有消费者都阻塞在sem_wait(items)调用上;生产者完成最后一件物品生产后调用sem_post(items),只会将items计数加1、唤醒等待队列中的1个消费者,被唤醒的消费者执行sem_wait(items)时会将计数再次减为0,其余消费者没有可用的信号量资源,且生产者已经不再执行post操作,就会永久阻塞在wait调用上。
规避方案
方案1:终止标记+批量唤醒
实现逻辑如下:
- 新增全局布尔标记
producer_stop,初始为false,读写该标记前需要加互斥锁保护 - 所有生产者完成生产任务后,先将
producer_stop设置为true,再调用和消费者总数量相等次数的sem_post(items),确保所有阻塞的消费者都能被唤醒 - 消费者每次
sem_wait(items)返回后,先加锁判断producer_stop是否为true且缓冲区为空,满足条件则直接退出消费逻辑,否则正常消费物品
方案2:哨兵值终止
该方案不需要额外的全局标记,逻辑耦合度更低:
- 提前约定特殊值作为终止哨兵(比如缓冲区存指针时用
NULL,存数值时用业务不可能出现的极端值) - 生产者完成所有正常物品生产后,往缓冲区中写入和消费者数量相等的哨兵值,每写入一个哨兵就调用一次
sem_post(items) - 消费者每次取出物品后先判断是否为哨兵值,是则直接退出消费流程,否则正常处理
方案3:超时等待主动检测
适合无法提前确认消费者数量的场景:
- 消费者使用
sem_timedwait()代替sem_wait(),设置合理的超时时间 - 每次超时返回后,检测生产者是否已经全部退出、缓冲区是否为空,两个条件同时满足则主动终止,否则继续等待
内容的提问来源于stack exchange,提问作者SteamedBun
相关产品推荐
相关产品推荐

