单生产者单消费者并发队列运行报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
相关产品推荐
相关产品推荐

