c++高性能阻塞队列

BlockQueue - 高并发环形缓冲阻塞队列

BlockQueue 是基于环形缓冲区实现的线程安全固定容量阻塞队列,采用单锁设计配合双条件变量机制,在保证线程安全的同时追求极致性能。适用于高吞吐低延迟的生产者-消费者场景。


git :BlockQueue - 高效线程安全阻塞队列

您的star是对该项目的肯定

核心特性

1. 高效内存模型

  • 预分配环形缓冲:初始化时一次性分配连续内存,构成环形单向链表
  • 64字节对齐:消除伪共享问题,提升多核缓存利用率
  • 条件析构优化:智能跳过trivial类型的析构调用

2. 精准并发控制

  • 单锁双条件变量
    • notEmptyCond:数据可读时唤醒消费者
    • notFullCond:空间可用时唤醒生产者
  • 自适应通知
    • 单元素操作使用notify_one减少上下文切换
    • 批量操作使用notify_all提高唤醒效率
  • 停止标志:支持即时优雅关闭

3. 完备操作接口

操作模式非阻塞无限等待超时等待
单元素入队push()wait_push()wait_push(timeout)
单元素出队pop()wait_pop()wait_pop(timeout)
批量入队pushBulk()wait_pushBulk()wait_pushBulk(timeout)
批量出队popBulk()wait_popBulk()wait_popBulk(timeout)

实现优势

1. 环形缓冲设计

+---+    +---+    +---+         +---+
| 0 | -> | 1 | -> | 2 | -> ... -> |N-1 |
+---+    +---+    +---+         +---+
  ^                             |
  |_____________________________|
  • O(1)时间复杂度:头尾指针移动完成入队/出队
  • 零动态分配:运行期间无内存管理开销
  • 缓存局部性:连续内存访问模式,预取友好

2. 条件析构优化

	template <typename T, bool IsTrivial = std::is_trivially_destructible<T>::value>
	struct DestroyHelper {
		static void destroy(T& obj) { obj.~T(); }
	};

	template <typename T>
	struct DestroyHelper<T, true> {
		static void destroy(T&) {}
	};

	template <typename T>
	void conditional_destroy(T& obj) {
		DestroyHelper<T>::destroy(obj);
	}
  • 对POD类型跳过析构

3. 批量操作优化

  • 单锁批量处理:减少锁竞争频率
  • 链式节点访问:直接操作内存连续的预分配节点
  • 友好内存布局:数据内存连续排列

使用示例

HSLL::BlockQueue<SensorData> queue;

// 初始化队列(容量1024)
if (!queue.init(1024)) {
    throw std::runtime_error("Queue init failed");
}

// 生产者线程
std::thread producer([&] {
    SensorData batch[BATCH_SIZE];
    while (true) {
        unsigned sent = queue.wait_pushBulk(batch, BATCH_SIZE);
        if (sent == 0) break; // 队列已停止
        // 处理未发送数据...
    }
});

// 消费者线程
std::thread consumer([&] {
    SensorData results[BATCH_SIZE];
    while (unsigned count = queue.wait_popBulk(results, BATCH_SIZE)) {
        process_batch(results, count);
    }
});

queue.stopWait(); // 优雅关闭
producer.join();
consumer.join();

接口规范

核心方法

方法说明
bool init(unsigned capacity)初始化队列容量(必须先于其他操作调用)
push()/pop()非阻塞操作,立即返回成功状态
wait_*()阻塞直到操作成功或队列停止
wait_*(timeout)限时等待版本
*Bulk()批量处理版本(建议优先使用以获得最佳性能)
void stopWait()触发停止状态并唤醒所有等待线程

模板要求

  • 元素类型需满足:
    • 可移动构造/拷贝构造函数
    • 构造/析构函数不抛异常

最佳实践

  1. 优先使用批量接口:相比单元素操作可提升3-5倍吞吐
  2. 合理设置容量:根据业务负载特征选择,建议为批次大小的整数倍
  3. 避免混合操作模式:同一队列不要混用阻塞/非阻塞接口,可能会影响队列效率
  4. 及时处理停止状态:调用stopWait()后需检查队列入/出栈操作的返回值
  5. 类型设计优化
    • 实现高效的移动构造函数
    • 保持较小尺寸(推荐≤64字节)

内部实现要点

内存管理

// Windows平台对齐分配
_aligned_malloc(sizeof(Node)*capacity, 64); 

// 其它平台对齐分配
aligned_alloc(64, sizeof(Node)*capacity);
  • 保证节点数组64字节对齐
  • 消除不同CPU核心间的缓存行竞争

条件变量使用

// 生产者等待空间
notFullCond.wait(lock, [this] { 
    return size != maxSize || isStopped; 
});

// 消费者等待数据
notEmptyCond.wait(lock, [this] {
    return size > 0 || isStopped;
});
  • 条件判断包含停止状态,避免死锁
  • 使用predicate模式防止虚假唤醒

注意事项

  1. 初始化要求:必须成功调用init()后才可进行其他操作
  2. 线程安全范围:不同队列实例之间无锁竞争
  3. 对象生命周期
    • 入队时构造对象(placement new)
    • 出队后立即析构(条件触发)
  4. 异常安全
    • 元素构造函数不应抛出异常
    • 队列操作保证强异常安全保证
  5. 不可复制设计:队列实例禁止拷贝构造和赋值操作
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值