并发工具 — MpscQueue 无锁队列 & ObjectPool 对象池
第17 课:并发工具 — MpscQueue 无锁队列 & ObjectPool 对象池 对应源文件: trantor/utils/LockFreeQueue.h — MpscQueue<T>:无锁多生产者单消费者队列 trantor/utils/ObjectPool.h — ObjectPool<T>:共享指针驱动的对象池 一、为什么需要这两个工具? 在高性能网络库中,有两类性能瓶颈反复出现: 瓶颈 1:跨线程任务投递 EventLoop::runInLoop() 每秒可能被调用数十万次(每个连接的读写完成都要回调)。如果用 mutex 保护投递队列,大量线程争锁会造成显著延迟。 → 解决方案:MpscQueue<T> 无锁队列,多线程投递不需要 mutex。 瓶颈 2:高频内存分配 HTTP 框架每个请求都要 new HttpRequest、new HttpResponse,请求完成立刻 delete。频繁的堆分配/释放不仅慢,还会造成内存碎片。 → 解决方案:ObjectPool<T> 对象池,释放时归还而不销毁,下次直接复用。 二、MpscQueue — 无锁多生产者单消费者队列 2.1 完整实现(共 ~115 行) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 template <typename T> class MpscQueue : public NonCopyable { private: struct BufferNode { BufferNode() = default; BufferNode(const T &data) : dataPtr_(new T(data)) {} BufferNode(T &&data) : dataPtr_(new T(std::move(data))) {} T *dataPtr_; // 堆上的数据 std::atomic<BufferNode *> next_{nullptr}; }; std::atomic<BufferNode *> head_; // 指向最新插入的节点 std::atomic<BufferNode *> tail_; // 指向最旧的哨兵节点(消费端) }; 2.2 初始状态 1 2 3 4 MpscQueue() : head_(new BufferNode), // 创建哨兵节点 tail_(head_.load(std::memory_order_relaxed)) // tail = head = 哨兵 {} 初始状态: ...