concurrentqueue源码阅读

并发队列实现与优化
本文详细介绍了并发队列ConcurrentQueue的构造过程,包括两种构造函数的实现,以及如何通过哈希表和链表优化线程安全的入队和出队操作。在入队操作中,通过隐式生产者哈希表进行高效查找和内存管理,避免了不必要的锁竞争。出队操作采用启发式策略选择最佳的生产者,以降低等待时间。这些设计确保了在高并发场景下,ConcurrentQueue能提供高效稳定的服务。

1、ConcurrentQueue构造

template <typename T, typename Traits = ConcurrentQueueDefaultTraits>
class ConcurrentQueue
// 三种构造函数:两个有参一个移动构造,禁止拷贝构造和赋值
// 有参构造函数的步骤大同小异,都是对哈希和链表(变量名叫list,但是是连续的内存)初始化,哈希的每个key在
// populate_initial_implicit_producer_hash()函数内都初始化为0
// 在populate_initial_block_list中先申请堆内存,然后再用placement new对每个内存进行初始化
explicit ConcurrentQueue(size_t capacity = 32 * BLOCK_SIZE)
			: producerListTail(nullptr),
			  producerCount(0),
			  initialBlockPoolIndex(0),
			  nextExplicitConsumerId(0),
			  globalExplicitConsumerOffset(0)
{
   
   
	implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed);
	populate_initial_implicit_producer_hash();
	populate_initial_block_list(capacity / BLOCK_SIZE + ((capacity & (BLOCK_SIZE - 1)) == 0 ? 0 : 1));
}

// 
ConcurrentQueue(size_t minCapacity, size_t maxExplicitProducers, size_t maxImplicitProducers)
			: producerListTail(nullptr),
			  producerCount(0),
			  initialBlockPoolIndex(0),
			  nextExplicitConsumerId(0),
			  globalExplicitConsumerOffset(0)
{
   
   
	implicitProducerHashResizeInProgress.clear(std::memory_order_relaxed);
	populate_initial_implicit_producer_hash();
	size_t blocks = (((minCapacity + BLOCK_SIZE - 1) / BLOCK_SIZE) - 1) * (maxExplicitProducers + 1) + 2 * (maxExplicitProducers + maxImplicitProducers);
	populate_initial_block_list(blocks);
}

2、enqueue压入数据

// 压入大同小异,只分析一种
inline bool enqueue(T const &item)
{
   
   
	MOODYCAMEL_CONSTEXPR_IF(INITIAL_IMPLICIT_PRODUCER_HASH_SIZE == 0)
	return false; // 直接看inner_enqueue()
	else return inner_enqueue<CanAlloc>(item);
}

inline bool inner_enqueue(U &&element)
{
   
   
	auto producer = get_or_add_implicit_producer();
	return producer == nullptr ? false : 
		producer->ConcurrentQueue::ImplicitProducer::template enqueue<canAlloc>(std::forward<U>(element));
	// producer是一个容器,真正将元素压到队列中是enqueue函数
}

// 压入的重点在get_or_add_implicit_producer()
// 获取值存放的内存
ImplicitProducer *get_or_add_implicit_producer()
{
   
   
	auto id = details::thread_id(); // 固定值,同一个线程id相同
	auto hashedId = details::hash_thread_id(id); // 经过计算后的hash值也相同
	/*
		implicitProducerHash是一个原子对象,存放的是ImplicitProducerHash的地址值
		ImplicitProducerHash是一个结构体,成员prev指向下一个ImplicitProducerHash
		每个ImplicitProducerHash都有一个hash数组,
		一下就是遍历链表每个节点,找到与id相同的,然后再将value存放到哈希表,
		如果已经存满会跳出循环,然后对哈希表进行扩容,每次扩容会将容量乘2
	*/
	auto mainHash = implicitProducerHash.load(std::memory_order_acquire);
	assert(mainHash != nullptr); // silence clang-tidy and MSVC warnings (hash cannot be null)
	for (auto hash = mainHash; hash != nullptr; hash = hash->prev)
	{
   
   
		// Look for the id in this hash
		auto
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值