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

单生产者单消费者并发队列运行报SIGSEGV段错误求助

根因分析

1. getCount逻辑错误导致队列无限制写入

当前的getCount计算逻辑完全错误:对于无限递增的读写指针设计,队列真实元素个数应为无符号数减法结果mWritePtr - mReadPtr(无符号整数溢出是C++标准明确定义的行为,结果正确)。你写的三元判断逻辑mWritePtr > mReadPtr ? 减 : 读减写会得到完全错误的元素数值,导致busyWaitForPush的队列满判断永远不触发,生产者持续写入覆盖队列已有位置,直接引发数据污染。

2. 读写指针无原子保护,存在数据竞争

mReadPtr和mWritePtr没有声明为原子类型,也没有加锁保护,多线程并发读写时会出现可见性问题、撕裂读(torn read),属于C++标准未定义行为,可能读到完全错误的指针数值。

3. pop返回引用导致访问野指针

pop返回队列内部存储的元素引用,你在返回前已经对mReadPtr执行了自增,该位置立刻就可以被生产者写入新值,消费者拿到引用后读取到的已经是被覆写的垃圾值。你存的是std::function指针,垃圾指针被解引用、delete时会直接破坏堆内存的元数据,后续调用new/malloc访问损坏的堆结构就会触发段错误,和你提供的gdb栈完全匹配。

修复方案

步骤1:新增原子头文件

#include <atomic>

步骤2:修改读写指针为原子类型

// 替换原来的uint64_t声明
std::atomic<uint64_t> mReadPtr = 0;
std::atomic<uint64_t> mWritePtr = 0;

步骤3:修正getCount逻辑

uint64_t getCount() const {
    return mWritePtr.load(std::memory_order_relaxed) - mReadPtr.load(std::memory_order_relaxed);
}

步骤4:修正peek的原子读取

bool peek() const {
    return mWritePtr.load(std::memory_order_acquire) != mReadPtr.load(std::memory_order_acquire);
}

步骤5:修改pop返回值为值类型,避免引用失效

// 把返回值从const T&改成T
T pop() {
    if (!peek()) {
        return mEmpty;
    }
    std::lock_guard<std::mutex> lock(mLock);
    if (!peek()) {
        return mEmpty;
    }
    T ret = mMem[mReadPtr.load(std::memory_order_relaxed) & mRingModMask];
    mReadPtr.fetch_add(1, std::memory_order_release);
    return ret;
}

修改后重新编译即可解决段错误问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 10:06:03