对中心资源层的GetRangeMemory与GetOneSpan进行锁优化

        原本,当线程资源层ThreadCache向中心资源层CentreCache申请资源时,中心资源层会在返回给线程资源层的内存的函数GetRangeMemory中加上桶锁,在GetRangeMemory内可能调用GetOneSpan向页缓存资源层申请资源,此时又会加上页缓存资源层的全锁。

现在,进行优化:

  • 优化原因:当CentreCache调用GetOneSpan向页缓存资源层申请资源时,CentreCache的桶锁未解开,这样其他线程闲置的资源就放不会这个桶里了,影响效率
  • 优化步骤:当CentreCache调用GetOneSpan向页缓存资源层申请资源时,解开桶锁,当CentreCache成功向页缓存资源层申请资源后,重新申请桶锁,再将申请来的多余资源插入进桶中
size_t CentreCache::GetRangeMemory(void*& start, void*& end, size_t n, size_t index,size_t alignedSize)//start、end为输出型参数,返回span内存包中分配出去的部分内存块链的起始和尾部,n代表要分配的内存块数量,index代表spanLists链的桶编号(与ThreadCache层的桶的编号是对应的),alignedSize为桶内所装内存块的大小,返回值为实际分配出去的内存块数量
{	
	spanLists[index].Getmutex().lock();//加上桶锁
	Span* sp = GetOneSpan(&spanLists[index], index,alignedSize);
	assert(sp);
	assert(sp->freelist != nullptr);
	size_t num = n-1;//end要下走的步数
	start = sp->freelist;
	end = start;
	while (num > 0 && NextNode(end) != nullptr)
	{
		--num;
		end = NextNode(end);
	}
	sp->freelist = NextNode(end);
	sp->usedBlocks += n - num;//n-num即为实际分配出去的内存块数量
	spanLists[index].Getmutex().unlock();
	return n - num;//n-num即为actualNumber
}
//GetOneSpan涉及中心资源层与页缓存资源层的交互,是线程竞争最激烈的地方,锁设计的必须精巧
Span* CentreCache::GetOneSpan(SpanList* sl, size_t index, size_t alignedSize)//从中心资源层找到一个符合线程资源层所申请的Span包,如没有,向页缓存资源层申请一个新的Span块
{	

	Span* oneSpan = spanLists[index].GetNoEmptySpan();
	if (oneSpan != nullptr)
		return oneSpan;

	spanLists[index].Getmutex().unlock();//向页缓存资源层申请新Span块的时候解开桶锁,以免耽误其他线程归还该桶里的Span块,这样可能会导致一个线程刚申请完Span还没来得及将Span块插入中心资源处桶里时,其他线程就又来申请新的Span块了,但无伤大雅,不处理这种情况更佳,省了下次再申请,反正多余的Span块也会被适时回收的
			
	PageCache::GetPageCache().GetPageCacheMUTEX().lock();//向页缓存资源层申请资源必须加全锁
	PageCache& pageCache = PageCache::GetPageCache();
	oneSpan = pageCache.NewSpan(SizeClass::PageCountCal(alignedSize));
	PageCache::GetPageCache().GetPageCacheMUTEX().unlock();
	//先假设,Span得页号是整个用户地址空间内的页号,并且它一定处于PageCache内申请来得内存块内,例通过(p+8K)/8K得来得页号
	//再假设,PageCache返回得Span块内只写好了PAGE_ID,而没有绑定好freelists
	char* start = (char*)(oneSpan->pageID << PAGE_SHIFT);
	char* end = start +(oneSpan->counts << PAGE_SHIFT);

	//将新申请来的Span块切割成每个大小为alignedSize的内存块
	char* cur = start;
	char* next = start + alignedSize;
	while (next < end)
	{	
		NextNode(cur) = next;
		cur = next;
		next = next + alignedSize;
	}
	NextNode(cur) = nullptr;
	oneSpan->freelist = (void*)(oneSpan->pageID << PAGE_SHIFT);
	//将新申请来的Span块插入到中心资源层对应SpanLists链中去
	spanLists[index].Getmutex().lock();//此处需要改变中心资源层桶链的结构,需要申请回桶锁.
	sl->PushFront(oneSpan);
	return oneSpan;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值