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

生产者生产单个项目后无法通知消费者,如何用Semaphore修复?

问题分析与修复方案

原代码的核心问题并非信号量的通知逻辑错误,而是共享队列未做线程安全保护:生产者与消费者对std::queue的并发操作存在数据竞争,加上线程调度的不确定性,导致消费者无法及时感知到生产者添加的单个元素,直到缓冲区被填满。结合Semaphore和互斥锁可以解决这个问题。

修复后的代码

#include <iostream>
#include <queue>
#include <semaphore.h>
#include <thread>
#include <functional>
#include <mutex>
#include <ctime>

const int BUFFER_SIZE = 3;

class Buffer {
public:
    sem_t sem_available_slots; // 可用空位数量
    sem_t sem_available_items; // 已生产元素数量
    std::queue<int> buffer;
    std::mutex mtx; // 保护队列的互斥锁

    Buffer() {
        sem_init(&sem_available_slots, 0, BUFFER_SIZE);
        sem_init(&sem_available_items, 0, 0);
    }

    ~Buffer() {
        sem_destroy(&sem_available_slots);
        sem_destroy(&sem_available_items);
    }

    void producer() {
        for (int i = 0; i < BUFFER_SIZE; ++i) {
            sem_wait(&sem_available_slots); // 等待有空位
            int item = rand() % 10;

            // 加锁后操作队列,避免数据竞争
            std::lock_guard<std::mutex> lock(mtx);
            buffer.push(item);
            std::cout << "Producer added " << item << std::endl;

            sem_post(&sem_available_items); // 通知消费者有新元素
        }
        std::cout << "Producer finished all items, terminating thread" << std::endl;
    }

    void consumer() {
        for (int i = 0; i < BUFFER_SIZE; ++i) {
            sem_wait(&sem_available_items); // 等待有元素可消费

            // 加锁后操作队列
            std::lock_guard<std::mutex> lock(mtx);
            int item = buffer.front();
            buffer.pop();
            std::cout << "Consumer removed " << item << std::endl;

            sem_post(&sem_available_slots); // 通知生产者有空位
        }
        std::cout << "Consumer finished all items, terminating thread" << std::endl;
    }
};

int main() {
    srand(time(nullptr)); // 初始化随机数种子
    Buffer buffer;
    std::thread producer_thread(&Buffer::producer, &buffer);
    std::thread consumer_thread(&Buffer::consumer, &buffer);

    producer_thread.join();
    consumer_thread.join();

    return 0;
}

关键修改说明

  • 添加线程安全保护:用std::mutex和std::lock_guard包裹所有对buffer的操作,确保同一时间只有一个线程能访问队列,彻底解决数据竞争问题。
  • 信号量逻辑优化:重命名信号量为sem_available_slots和sem_available_items,分别对应缓冲区空位和已生产元素数量,逻辑更直观,避免命名混淆。
  • 调整循环逻辑:将原无限循环改为固定次数循环,明确生产/消费的元素总量,避免线程异常阻塞或无限运行。
  • 初始化随机数种子:确保每次运行生成不同的随机元素,便于观察执行效果。

修复后,生产者每生产一个元素就会立即唤醒消费者,消费者无需等待缓冲区填满即可开始消费,完全符合生产者-消费者的同步预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 03:35:22