五、高并发内存池--Thread Cache

五、高并发内存池–Thread Cache

5.1 Thread Cache的工作原理

thread cache是哈希桶结构,每个桶是一个按桶位置映射大小的内存块对象的自由链表。每个线程都会有一个thread cache对象,这样每个线程在这里获取对象和释放对象时都是无锁的。
在这里插入图片描述
每一个线程都有一个自己的Thread Cache,即每个线程在向自己的Thread Cache申请内存时是线程安全的,无需加锁,线程之间是不会相互产生影响的,所以大大加快了申请内存的效率。但是每一个线程是在什么时候创建这个自己的Thread Cache的呢?又是怎么创建的呢?
在C++中,_declspec(thread)是一个用于指定线程局部存储( Thread Local Storage,TLS)的关键字。通过将该关键字应用于变量声明,可以确保每个线程都拥有其自己的变量实例,而不是共享同一个变量实例。
具体来说,当变量声明为_declspec(thread)时,每个线程都会有一个独立的变量实例,该变量的生命周期与线程的生命周期一致。每个线程对该变量的访问都是线程安全的,不会与其他线程的访问冲突。
使用_declspec(thread)可以在多线程编程中很方便地创建和使用线程局部变量,它通常用于解决多线程环境下的共享数据问题。请注意,_declspec(thread)是Microsoft Visual C++编译器的特定语法,并不在标准的C++语言规范中定义。其他编译器可能有自己的实现或类似的机制。
也就是说在创建线程之前要先利用_declspec(thread)关键字声明一个静态的变量,这样在创建新的线程需要申请内存的时候就可以通过这个变量去自己专属的Thread Cache中申请内存了,_declspec(thread)声明的变量只会访问自己线程中的变量,不会访问别的线程中的变量,所以通过_declspec(thread)变量的访问是线程安全的,无需加锁。

5.2 ThreadCache.h

//线程缓存
class ThreadCache
{
public://向Thread Cache申请size个字节的内存void* Allocate(size_t size);//释放size个字节大小的内存到Thread Cache中void DeAllocate(void* obj, size_t size);//向中心缓存中下标为index位置的哈希桶中获取size个字节大小的内存块void* FetchFromCentralCache(size_t index, size_t size);//size代表线程申请的一个小对象的大小,自由链表太长就要向中心缓存中还一定量的内存void ListTooLong(FreeList& list, size_t size);private:FreeList _freeLists[NFREELIST];//每一个FreeList都是一个自由链表,_freeLists是一个挂满了自由链表的哈希桶数组
};//线程本地存储变量,_declspec(thread)声明的变量在每一个线程中独享一个
static _declspec(thread) ThreadCache* pTLSThreadCache = nullptr;

5.3 ThreadCache.cpp


//向Thread Cache申请size个字节的内存
void* ThreadCache::Allocate(size_t size)
{//计算向上对齐后的大小int alignSize = SizeClass::RoundUp(size);//计算所需大小的对象在哪一个哈希桶里面int index = SizeClass::Index(alignSize);//如果对应下标的哈希桶的自由链表中有内存对象,就直接弹出一个返回if (!_freeLists[index].Empty()){return _freeLists[index].Pop();}else//走到这里说明对应下标的哈希桶的自由链表中没有内存对象,需要找中心缓存拿{return FetchFromCentralCache(index, alignSize);}}void ThreadCache::ListTooLong(FreeList& list, size_t size)
{void* start = nullptr;void* end = nullptr;//链表太长,就取出来一部分还给centralcachelist.PopRange(start, end, list.MaxSize());//把start到end这一段链表还给centralcache对应位置的哈希桶中//因为CentralCache是所有线程共享一个的,所以把它设计成单例模式//即全局只有一个对象较好,CentralCache类提供GetInstance()函数//获取类指针调用成员函数CentralCache::GetInstance()->ReleaseListToSpans(start, size);}//释放内存到Thread Cache中
void ThreadCache::DeAllocate(void* obj, size_t size)
{assert(size <= MAX_BYTES);assert(obj);//计算归还的大小为size的内存块在哪一个哈希桶中size_t index = SizeClass::Index(size);//把obj插入到对应的哈希桶的自由链表中_freeLists[index].Push(obj);//如果还回来的小对象太多,导致自由链表太长,就应该还一部分给CentralCacheif (_freeLists[index].Size() >= _freeLists[index].MaxSize()){ListTooLong(_freeLists[index], size);}
}//向中心缓存获取内存块
void* ThreadCache::FetchFromCentralCache(size_t index, size_t size)
{//一次向CentralCache申请多个size大小的对象,那么一次要申请多少个呢?// 这要根据size的大小计算,如果size很小,那么一次就向CentralCache申请// 多一点,如果size很大,那么一次就申请少一点,那么如何计算一次申请多少呢?//这里需要使用慢增长的方式控制size_t batchNum = min(_freeLists[index].MaxSize(), SizeClass::NumMoveSize(size));if (batchNum == _freeLists[index].MaxSize()){_freeLists[index].MaxSize()++;//慢增长}//想要向CentralCache获取batchNum个size大小的对象void* start = nullptr;void* end = nullptr;//实际获取到的size大小的对象的数目int actualNum = CentralCache::GetInstance()->FetchRangeObj(start, end, batchNum, size);assert(actualNum > 0);//如果只获取到了一个size大小的对象,那么就直接返回给线程了if (actualNum == 1){assert(start == end);return start;}else{//如果获取到了多个内存块,就把start对应的内存块返回给线程//其余的都头插到threadcache对应映射位置的哈希桶的自由链表中/*NextObj(end) = _freeLists[index]._freeList;_freeLists[index]._freeList = start;*/_freeLists[index].PushRange(NextObj(start), end, actualNum - 1);return start;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/117206.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

查询优化器内核剖析之查询的执行与计划的缓存 Hint 提示

本篇议题如下: 查询的执行与计划的缓存 Hint 提示 首先看到第一个议题 查询的执行与计划的缓存 一旦查询被优化之后&#xff0c;存储引擎就使用选中的执行计划将结果返回&#xff0c;而被使用的这个执行 计划就会被保存在内存中一个被称之为“计划缓存”的地方&#xff0c;从…

MyBatis多表查询

1. 多表关系回顾 在项目开发当中一对一关系的表不常见&#xff0c;因为一对一关系的两张表通常会合并为一张表。 2. 一对一查询 一张表对应一个实体类&#xff0c;一个实体类对应一个Mapper接口。 例如&#xff1a;查询菜品&#xff0c;同时查询出该菜品所属的分类。 分析&…

F5服务器负载均衡能力如何?一文了解

但凡知道服务器负载均衡这个名词的&#xff0c;基本都知道 F5&#xff0c;因为负载均衡是 F5 的代表作&#xff0c;换句话来说&#xff0c;负载均衡就是由 F5 发明的。提到F5服务器负载均衡能力如何&#xff1f;不得不关注F5提出的关于安全、网络全面优化的解决方案&#xff0c…

07:STM32----ADC模数转化器

目录 1:简历 2:逐次逼近型ADC 3:ADC基本结构 4:输入通道 5:规则组的4种转换模式 1:单次转化,非扫描模式 2:连续转化,非扫描模式 3:单次转化,扫描模式 4:单次转化,扫描模式 6:触发控制 7:数据对齐 8:转化时间 9:校准 10:ADC的硬件电路 A: AD单通道 1:连接图 2:函…

水果库存系统(SSM+Thymeleaf版)

不为失败找理由&#xff0c;只为成功找方法。所有的不甘&#xff0c;因为还心存梦想&#xff0c;所以在你放弃之前&#xff0c;好好拼一把&#xff0c;只怕心老&#xff0c;不怕路长。 文章目录 一、前言二、系统架构与需求分析1、技术栈1.1 后端1.2 前端 2、需求分析 三、设计…

JavaWeb_LeadNews_Day10-Xxljob, Redis实现定时热文章

JavaWeb_LeadNews_Day10-Xxljob, Redis实现定时热文章 xxl-job概述windows部署调度中心docker部署调度中心 xxl-job入门案例xxl-job分片广播热点文章定时计算思路分析具体实现热文章计算定时计算 查询文章接口改造来源Gitee xxl-job概述 windows部署调度中心 运行 xxl-job\do…

字节美团题库之重排链表

文章目录 题目详情题目分析完整实现Java代码总结 题目详情 注&#xff1a;面试真实遇到&#xff0c;对于面试遇到算法时要冷静分析 LCR 026 给定一个单链表 L 的头节点 head &#xff0c;单链表 L 表示为&#xff1a; L0 → L1 → … → Ln-1 → Ln 请将其重新排列后变为&am…

解决npm install报错: No module named gyp

今天运行一个以前vue项目&#xff0c;启动时报错如下&#xff1a; ERROR Failed to compile with 1 error上午10:19:33 error in ./src/App.vue?vue&typestyle&index0&langscss& Syntax Error: Error: Missing binding D:\javacode\Springboot-MiMall-RSA\V…

如何设计一个好的游戏剧情(Part 1:主题的设定)

提醒&#xff1a;此教程仅仅为作者的一些经验和感悟&#xff0c;非专业教程&#xff0c;若介意请前往网上搜集或者书本查阅相关资料&#xff01; 前言&#xff1a;游戏为什么要有剧情——游戏剧情的重要性 游戏剧情的重要性难以低估。一个精彩的剧情可以让玩家感受到强烈的情感…

mac帧 arp

1.分片 2.MSS max segment size 3.跨网络的本质 就是经历很多的子网或者局域网 4.将数据从A主机跨网络送到B主机的能力 IP和mac IP解决的是路径选择的问题 5.数据链路层 用于两个设备&#xff08;同一种数据链路节点&#xff09;之间进行传递 6.以太网ether 7.局域网通…

python 深度学习 解决遇到的报错问题3

目录 一、AttributeError: The vocab attribute was removed from KeyedVector in Gensim 4.0.0. 二、ImportError: cannot import name logsumexp 三、FutureWarning: Passing (type, 1) or 1type as a synonym of type is deprecated; in a future version of numpy, it w…

单调递增的数字【贪心算法】

单调递增的数字 当且仅当每个相邻位数上的数字 x 和 y 满足 x < y 时&#xff0c;我们称这个整数是单调递增的。 给定一个整数 n &#xff0c;返回 小于或等于 n 的最大数字&#xff0c;且数字呈 单调递增 。 public class Solution {public int monotoneIncreasingDigits…

Citespace、vosviewer、R语言的文献计量学 、SCI

文献计量学是指用数学和统计学的方法&#xff0c;定量地分析一切知识载体的交叉科学。它是集数学、统计学、文献学为一体&#xff0c;注重量化的综合性知识体系。特别是&#xff0c;信息可视化技术手段和方法的运用&#xff0c;可直观的展示主题的研究发展历程、研究现状、研究…

9.2作业

QT实现闹钟 widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include<QTimerEvent> #include<QDateTime> #include<QLineEdit> #include<QLabel> #include<QPushButton> #include <QTextToSpeech> QT_BEGIN_NAMES…

word导出为HTML格式教程,同时也导出图片

在写文档教程时&#xff0c;有时需要借鉴人家的专业文档内容&#xff0c;一般都是word格式文档。word直接复制里面的内容&#xff0c;帐帖到网站编辑器会有很多问题&#xff0c;需要二次清楚下格式才行&#xff0c;而且图片是没办法直接复制到编辑器内的。所以最方便的办法是将…

面试官:说一下 MyBatis 的一级缓存和二级缓存 ?

目录 1. MyBatis 的缓存机制 2. 为什么不默认开启 MyBatis 的二级缓存 3. MyBatis 如何开启二级缓存 1. MyBatis 的缓存机制 MyBayis 中包含两级缓存&#xff1a;一级缓存和二级缓存 1. 一级缓存是 SqlSession 级别的&#xff0c;是 MyBatis 自带的缓存功能&#xff0c;默认…

在CentOS7上使用Docker安装和部署RabbitMQ

&#x1f680; 1 拉取RabbitMQ Docker镜像 首先&#xff0c;使用Docker命令从Docker Hub拉取RabbitMQ官方镜像。打开终端并运行以下命令&#xff1a; docker pull rabbitmq&#x1f680; 2 创建RabbitMQ容器 一旦镜像下载完成&#xff0c;使用以下命令创建RabbitMQ容器&…

x86 汇编手册快速入门

本文翻译自&#xff1a;Guide to x86 Assembly 在阅读 Linux 源码之前&#xff0c;我们需要有一些 x86 汇编知识。本指南描述了 32 位 x86 汇编语言编程的基础知识&#xff0c;包括寄存器结构&#xff0c;数据表示&#xff0c;基本的操作指令&#xff08;包括数据传送指令、逻…

【leetcode 力扣刷题】数学题之数的开根号:二分查找

用二分查找牛顿迭代解决开根号 69. x的平方根367. 有效的完全平方数 69. x的平方根 题目链接&#xff1a;69. x的平方根 题目内容&#xff1a; 题意是要我们求一个数的算数平方根&#xff0c;但是不能使用内置函数&#xff0c;那么我们就暴力枚举。我们知道如果y>2的话&am…

PO设计模式是selenium自动化测试中最佳的设计模式之一

Page Object Model&#xff1a;PO设计模式是selenium自动化测试中最佳的设计模式之一&#xff0c;主要体现在对界面交互细节的封装&#xff0c;也就是在实际测试中只关注业务流程就OK了传统的设计中&#xff0c;在新增测试用例之后&#xff0c;代码会有以下几个问题&#xff1a…