- 博客(262)
- 收藏
- 关注
原创 B+树和B树
B+树是B树的变形,是在B树基础上优化的多路平衡搜索树,B+树的规则跟B树基本类似,但是又在B树的基础上做了以下几点改进优化:\2. 分支节点的子树指针与关键字个数相同\3. 分支节点的子树指针p[i]指向关键字值大小在[k[i],k[i+1])区间之间\4. 所有叶子节点增加一个链接指针链接在一起\5. 所有关键字及其映射数据都在叶子节点出现**B+**树的特性:\1. 所有关键字都出现在叶子节点的链表中,且链表中的节点都是有序的。\2. 不可能在分支节点中命中。\3. 分支节点相当于是叶子节点的索引,叶
2025-08-30 16:10:28
358
原创 B-树(上半部分)
1. 如果树为空,直接插入新节点中,该节点为树的根节点\2. 树非空,找待插入元素在树中的插入位置(注意:找到的插入节点位置一定在叶子节点中)\3. 检测是否找到插入位置(假设树中的key唯一,即该元素已经存在时则不插入)\4. 按照插入排序的思想将该元素插入到找到的节点中\5. 检测该节点是否满足B-树的性质:即该节点中的元素个数是否等于M,如果小于则满足\6. 如果插入后节点不满足B树的性质,需要对该节点进行分裂:申请新节点找到该节点的中间位置。
2025-08-30 14:45:21
222
原创 Qt中的锁(1)
加了锁之后,第一个线程顺利拿到锁继续执行++,此时第二个线程要进来就会阻塞,直到第一个线程释放锁才会放第二个进入,把第二个线程从阻塞中释放。其中num是一个两个线程访问的公共变量,之前如果是并发执行,第一个改变,第二个也会改变,就会出现问题。加锁,把多个要访问的公共资源通过锁保护起来,把并行执行变成串行执行,多个线程执行加锁的对象得是同一个对象,不同对象不会互斥。
2025-08-30 12:34:51
196
原创 QThread的使用(1)
Qt中的多线程和linux中的线程本质是一样的,Linux中实现多线程是用系统提供的pthread库,Qt对其进行了封装,C++11中也引入了std::thread。QThread创建线程的时候,需要重点指定线程的入口函数,创建QThread的子类,重写其中的run函数,这属于是多态。Qt中的多线程参考了java的多线程。定时器内部本质是多线程。
2025-08-30 00:57:04
195
原创 高并发内存池(19)-用基数树优化
这段代码展示了内存池中的关键操作(分配Span、回收Span、合并Span),通过对比优化前后的实现,我们可以清晰地看到性能提升的关键点。
2025-08-29 19:00:10
206
原创 高并发内存池(17)-使用定长内存池配合脱离new
空间换时间预分配内存牺牲部分空间换取运行时极致的分配速度专有化分配为Span对象定制分配器避免通用分配器的开销生命周期控制对象池管理Span的创建销毁避免频繁系统调用与三级缓存协同graph LRA[ThreadCache] -->|批量| B[CentralCache]C -->|ObjectPool| D[预分配Span]定长池作为基础设施支撑上层缓存。
2025-08-29 14:23:35
230
原创 高并发内存池(12)-ThreadCache回收内存
使用引用参数需要修改调用方的变量需要返回两个值(链表头和尾)语法简洁且类型安全性能零开销代码可读性好这是C++中常用的"输出参数"模式,特别适合需要返回多个值的场景。在内存池这种高性能组件中,这种设计确保了接口的效率和简洁性。
2025-08-27 23:48:29
319
原创 高并发内存池(11)-PageCache获取Span(下)
持有锁的时间应该尽可能短通过精细的锁粒度控制,在保证线程安全的前提下,最大化并发性能。这是高性能内存分配器设计的精髓之一。
2025-08-27 21:26:24
141
原创 高并发内存池(9)-PageCache获取(上)
GetOneSpan从中心缓存的指定Span链表中获取一个的Span。如果没有可用Span,则向页缓存(PageCache)申请新的Span并进行切分。
2025-08-27 15:48:09
1191
原创 高并发内存池(8)-PageCache的整体设计
需要注意的是central cache和page cache 的核⼼结构都是spanlist的哈希桶,但是他们是有本质区别的,central cache中哈希桶,是按跟thread cache⼀样的⼤⼩对⻬关系映射的,他的spanlist中挂的span中的内存都被按映射关系切好链接成⼩块内存的⾃由链表。⽽page cache 中的spanlist则是按下标桶号映射的,也就是说第i号桶中挂的span都是i⻚内存。被多个文件包含出现冲突。
2025-08-27 01:10:32
526
原创 高并发内存池(7)- CentralCache的核心设计
这个函数从中心缓存获取一批(batchNum个)指定大小(size)的内存对象,通过start和end指针返回这批对象的起始和结束位置。
2025-08-26 21:23:32
328
原创 高并发内存池(6)- CentralCache结构设计
无论是32位还是64位的 Windows 操作系统,只要使用 MSVC 编译器编译 Windows 应用程序,都会定义 _WIN32 宏。因此,你可以在代码中使用条件编译来判断是否为 Windows 环境,而不需要区分具体是32位还是64位的 Windows。当使用 MSVC 编译器编译 Windows 应用程序时,无论是 32 位还是 64 位的 Windows 环境,_WIN32 宏都会被定义。当使用 MSVC 编译器编译 64 位的 Windows 应用程序时,_WIN64 宏会被定义。
2025-08-26 15:52:18
466
原创 高并发内存池(5)-CentralCache的整体设计
central cache也有⼀个哈希映射的spanlist,spanlist中挂着span,从span中取出对象给thread cache,这个过程是需要加锁的,不过这⾥使⽤的是⼀个桶锁,尽可能提⾼效率。central cache映射的spanlist中所有span的都没有内存以后,则需要向page cache申请⼀个新的span对象,拿到span以后将span管理的内存按⼤⼩切好作为⾃由链表链接到⼀起。然后从span中取对象给thread cache。以⻚为单位的⼤内存管理span的定义。
2025-08-26 00:46:27
452
原创 高并发内存池(4)-TLS:Thread Local Storage
(TLS),是一种变量的存储方法,这个变量在它所在的线程内是全局可访问的,但是不能被其他线程访问到,这样就保持了数据的线程独立性。进程里面也会有多个线程,怎么解决序号问题,如果同时来创建,也会遇到锁的问题,这时候要借助TLS。目前使用TLS的方法有多种,POSIX的pthread.h提供了一组API来实现此功能。,是所有线程都可以访问的,这样就不可避免需要锁来控制,增加了控制成本和代码复杂度。除了API的方式,GCC的编译器也支持语言级别的用法,这样比用API调用,更简单。
2025-08-25 21:16:02
192
原创 高并发内存池(3)-ThreadCache哈希桶映射对齐规则
如果是在128字节以内,就是128%8=16,所以有16个桶,如果大于128,比如1024,(1024-128)%16=56,要减去前面的128是因为前面不是一样的计算方法。比如有129个字节,差15个就可以对齐,就要浪费十五个字节,15%144大概在10%左右。如在1-8所以在二进制中最后三位一定取0,最高位是8,所以能够对齐。这里可以数字计算如:1/8=0+1再×8=8,就可以对齐了。百分之10的浪费是如何计算的呢?移位运算符效率高,相比于乘法。
2025-08-25 17:35:57
526
原创 高并发内存池(2)-ThreadCache的整体设计
/ 这个宏定义非常重要!它用于访问对象头部的指针这个宏的作用是:将obj强制转换为void**类型,然后解引用,这样就可以读写obj地址处存储的值(即下一个节点的地址)。
2025-08-25 00:51:16
493
原创 高并发内存池(1)-定长内存池
不用结构体,用其内存块当节点,用头四个或者八个节点存储下一个位置的地址,这时候需要处理如果只剩最后一个会不会越界的情况,这时候我们需要引入新的成员变量remianBytes来知道剩余内存的大小,*表示的是指针,指针代表的是地址,它的指向需要有意义, *的前面表示的是类型,void * 没有意义,既不能解引用又不能进行加减。整体的流程:先看freeList有没有空余的,先进行头删,然后再到_memory里面去切,如果没有多余的,就去找系统申请大块内存。_memory:表示一大块内存,需要确定使用的变量类型。
2025-08-24 21:03:45
385
原创 浏览器发送网页详细过程分解
graph TDA[用户输入URL并回车] --> B[DNS解析]B --> C[获取服务器IP地址]C --> D[TCP三次握手]D --> E[发送HTTP请求]E --> F[服务器处理并返回响应]F --> G[浏览器解析渲染]subgraph G [浏览器解析渲染]G1[解析HTML构建DOM树]G2[解析CSS构建CSSOM树]G3[合并生成渲染树]G4[布局 Layout]G5[绘制 Painting]endG --> H[TCP四次挥手断开连接]
2025-08-24 15:47:26
928
原创 仿视频播放平台播放器(1)
使⽤QT6框架实现多端兼容的友好桌⾯,集成libmpv多媒体内核完成视频播放与控制,借助HTTP协议完成与服务器的数据交互,⽀持实时弹幕增加观看趣味,旨在为⽤⼾提供⼀个集视频上传、播放和社交互动于⼀体的播放平台。
2025-08-24 15:29:13
340
原创 CMake 命令⾏⼯具介绍
Step 0:⽬录结构Step 1:新建⽂件-main.cppStep 2:新建⽂件-test.cppStep 3:修改⽂件-CMakeLists.txt。
2025-08-23 12:44:28
856
原创 CMake 快速开始
编辑环境:VS Code编译环境:VS Code Remote SSH模式 + Ubuntu 24.04CMake 官⽅源代码下载地址:https://cmake.org/download/CMake 官⽅英⽂ 档地址:https://cmake.org/cmake/help/latest/index.htmlStep 2:验证安装:安装完成后,可通过以下命令验证 CMake 是否安装成功以及查看其版本。
2025-08-22 19:14:16
489
原创 CMake⼯程介绍
CMake 语法简单易上⼿,功能强⼤,使⽤⼴泛,IDE⽀持度⾼,已经是C/C++事实上的构建标准,也是⼀个⼗分重要的C/C++⼯程管理⼯具。学好CMake,不但使你的C/C++⼯程优雅⾼效,也能提升你的个⼈竞争⼒。下图展⽰了:主流C++商业级开发IDE 对CMake的⽀持情况。⼀个⼗分重要的C/C++⼯程管理⼯具。⽩话CMake-真实世界⾥的例⼦。场景:我们要编译我们的⼯程。CMake 还有哪些优势。
2025-08-22 17:20:10
220
原创 epoll 工作方式
如果服务端写的代码是阻塞式的 read, 并且一次只 read 1k 数据的话(read 不能保证一次就把所有的数据都读出来, 参考 man 手册的说明, 可能被信号打断), 剩下的 9k 数据就会待在缓冲区中.• 如上面的例子, 虽然只读了 1K 的数据, 缓冲区还剩 1K 的数据, 在第二次调用epoll_wait 的时候, epoll_wait 不会再返回了.epoll 的高性能, 是有一定的特定场景的. 如果场景选择的不适宜, epoll 的性能可能适得其反.(亲妈, 水平触发)
2025-08-22 15:39:33
721
原创 多路转接 epoll
• 事件回调机制: 避免使用遍历, 而是使用回调函数的方式, 将就绪的文件描述符结构加入到就绪队列中, epoll_wait 返回直接访问就绪队列就知道哪些文件描述符就绪. 这个操作时间复杂度 O(1). 即使文件描述符数目很多, 效率也不会受到影响.• 这些事件都会挂载在红黑树中,如此,重复添加的事件就可以通过红黑树而高效的识别出来(红黑树的插入时间效率是 logn,其中 n 为树的高度).• 它不同于 select()是在监听事件时告诉内核要监听什么类型的事件, 而是在这里先注册要监听的事件类型.
2025-08-20 21:29:02
826
原创 用poll改写select
的经典高性能网络场景(例如 IM、推送服务、HTTP长连接网关)时,性能会急剧下降。的最大痛点——文件描述符数量限制,并提供了更清晰的事件管理接口。通常只是一个过渡选择,最终都会走向。在现代Linux高性能网络编程中,的一些表面问题,但它与。
2025-08-19 22:45:24
820
原创 多路转接 select
○ 二是 select 返回后会把以前加入的但并无事件发生的 fd 清空,则每次开始select 前都要重新从 array 取得 fd 逐一加入(FD_ZERO 最先),扫描 array 的同时取得 fd 最大值 maxfd,用于 select 的第一个参数。理解 select 模型的关键在于理解 fd_set,为说明方便,取 fd_set 长度为 1 字节,fd_set中的每一 bit 可以对应一个文件描述符 fd。• (2)若 fd=5,执行 FD_SET(fd,&set);
2025-08-19 22:24:40
906
原创 五种 IO 模型与阻塞 IO
• 是为完成某种任务而建立的两个或多个线程,这个线程需要在某些位置上协调他们的工作次序而等待、传递信息所产生的制约关系. 尤其是在访问临界资源的时候。. 而且在实际的应用场景中, 等待消耗的时间往往都远远高于拷贝的时间. 让 IO 更高效, 最核心的办法就是让等待的时间尽量少.• 阻塞 IO: 在内核将数据准备好之前, 系统调用会一直等待. 所有的套接字, 默认都是阻塞方式.• 阻塞调用是指调用结果返回之前,当前线程会被挂起. 调用线程只有在得到结果之后才会返回.
2025-08-19 01:10:28
746
原创 NAT、代理服务、内网穿透(2)
• 正向代理(Forward Proxy)是一种常见的网络代理方式,它位于客户端和目标服务器之间,代表客户端向目标服务器发送请求。正向代理服务器接收客户端的请求,然后将请求转发给目标服务器,最后将目标服务器的响应返回给客户端。通过这种方式,正向代理可以实现多种功能,如提高访问速度、隐藏客户端身份、实施访问控制等。
2025-08-18 18:41:23
918
原创 NAT、代理服务、内网穿透
那么问题来了, 如果局域网内, 有多个主机都访问同一个外网服务器, 那么对于服务器返回的数据中, 目的 IP 都是相同的. 那么 NAT 路由器如何判定将这个数据包转发给哪个局域网的主机?这种关联关系也是由 NAT 路由器自动维护的. 例如在 TCP 的情况下, 建立连接时, 就会生成这个表项;• 很多学校, 家庭, 公司内部采用每个终端设置私有 IP, 而在路由器或必要的服务器上设置全局 IP;• 在 NAT 路由器内部, 有一张自动生成的, 用于地址转换的表;• 装换表的生成和销毁都需要额外开销;
2025-08-18 11:03:58
570
原创 数据链路层(2)
• 源主机发出 ARP 请求,询问“IP 地址是 192.168.0.1 的主机的硬件地址是多少”,并将这个请求广播到本地网段(以太网帧首部的硬件地址填 FF:FF:FF:FF:FF:FF 表示广播);• 在网卡出厂时就确定了, 不能修改. mac 地址通常是唯一的(虚拟机中的 mac 地址不是真实的 mac 地址, 可能会冲突;• 目的主机接收到广播的 ARP 请求,发现其中的 IP 地址与本机相符,则发送一个ARP 应答数据包给源主机,将自己的硬件地址填写在应答包中;
2025-08-17 23:05:22
663
原创 数据链路层(1)
• “以太网” 不是一种具体的网络, 而是一种技术标准;既包含了数据链路层的内容, 也包含了一些物理层的内容. 例如: 规定了网络拓扑结构, 访问控制方式, 传输速率等;• 源地址和目的地址是指网卡的硬件地址(也叫 MAC 地址), 长度是 48 位,是在网卡出厂时固化的;• 以太网是当前应用最广泛的局域网技术;把数据从一个主机到另一个主机是局域网要解决的问题,在数据链路层解决。• 帧协议类型字段有三种值,分别对应 IP、ARP、RARP;IP解决的是B到C为什么要先到路由器F的问题。
2025-08-17 19:47:19
320
原创 IP 分片和组装的具体过程
• 13 位分片偏移(framegament offset): 是分片相对于原始 IP 报文开始处的偏移. 其实就是在表示当前分片在原报文中处在哪个位置. 实际偏移的字节数是这个值 除以 8 得到的. 因此, 除了最后一个报文之外(之前如果都是 8 的整数倍,最后一片的偏移量也一定是 8 的整数倍), 其他报文的长度必须是 8 的整数倍(否则报文就不连续了).• 16 位标识(id): 唯一的标识主机发送的报文. 如果 IP 报文在数据链路层被分片了, 那么每一个片里面的这个 id 都是相同的.
2025-08-17 16:24:08
1050
原创 IP(2)
• 有一种技术叫做 DHCP, 能够自动的给子网内新增主机节点分配 IP 地址, 避免了手动管理 IP 的不便.• 一般的路由器都带有 DHCP 功能. 因此路由器也可以看做一个 DHCP 服务器.过去曾经提出一种划分网络号和主机号的方案, 把所有 IP 地址分为五类, 如下图所示(该图出 自[TCPIP])。• A 类 0.0.0.0 到 127.255.255.255• B 类 128.0.0.0 到 191.255.255.255。
2025-08-17 02:00:47
587
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人