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

单生产者多消费者FIFO队列锁机制异常问题求助

单生产者多消费者FIFO队列崩溃问题排查与修复

问题根源

  • 无锁状态下读取队列大小:get()和put()方法中,对my_queue.size()的检查都未加锁保护。以get()为例:当多个消费者线程同时看到队列非空(my_queue.size() != 0),其中一个线程先获取锁并取走最后一个元素,后续线程获取锁时队列已为空,此时调用my_queue.front()会触发未定义行为(崩溃)。
  • 检查与操作的原子性被破坏:队列状态检查和后续的入队/出队操作必须在同一个锁的保护下,否则两次操作之间的队列状态可能被其他线程修改,导致逻辑错误。

修复后的代码

#pragma once
#include <optional>
#include <queue>
#include <mutex>
#include <condition_variable>

template<class T, uint32_t MAX_SIZE>
class spmc_fifo_queue
{
public:
    using optional_queue_pair = std::optional<T>;

    bool put(optional_queue_pair&& p)
    {
        std::unique_lock my_lock(my_mutex);
        // 等待队列有空闲空间,条件判断在锁保护下执行
        my_cv_remove.wait(my_lock, [this] { return my_queue.size() < MAX_SIZE; });
        
        my_queue.push(std::move(p));
        my_cv_add.notify_one();
        return true;
    }

    optional_queue_pair get()
    {
        std::unique_lock my_lock(my_mutex);
        // 等待队列非空,条件判断在锁保护下执行
        my_cv_add.wait(my_lock, [this] { return my_queue.size() != 0; });
        
        optional_queue_pair ret = std::move(my_queue.front());
        my_queue.pop();
        my_cv_remove.notify_one();
        return ret;
    }

private:
    std::queue<optional_queue_pair> my_queue;
    std::mutex my_mutex;
    std::condition_variable my_cv_add;
    std::condition_variable my_cv_remove;
};

关键修改说明

  • 移除无锁状态检查:直接使用std::unique_lock获取锁,调用wait()方法——wait()会自动释放锁并等待条件,被唤醒后重新获取锁并检查条件,确保条件满足后才继续执行。
  • 合并锁的作用范围:将队列状态检查、入队/出队操作全部放在同一个锁的保护下,保证这些操作的原子性,彻底避免竞态条件。
  • 清理冗余定义:移除原代码中多次重复定义的optional_queue_pair,仅在类的public区域定义一次,提升代码整洁度。

补充说明

  • std::condition_variable::wait()的谓词参数会在线程被唤醒后重新检查,能有效避免虚假唤醒带来的逻辑问题。
  • 单生产者多消费者场景下,notify_one()足以唤醒一个等待的消费者线程;若扩展为多生产者场景,可根据需求改用notify_all(),但会带来一定性能开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 20:02:09