- 博客(79)
- 收藏
- 关注
原创 多线程编程实战:基于阻塞队列与环形队列的生产者消费者模型详解
⽣产者消费者模式就是通过⼀个容器来解决⽣产者和消费者的强耦合问题。⽣产者和消费者彼此之间不直接通讯,⽽通过阻塞队列来进⾏通讯,所以⽣产者⽣产完数据之后不⽤等待消费者处理,直接扔给阻塞队列,消费者不找⽣产者要数据,⽽是直接从阻塞队列⾥取,阻塞队列就相当于⼀个缓冲区,平衡了⽣产者和消费者的处理能⼒。这个阻塞队列就是⽤来给⽣产者和消费者解耦的。
2025-04-01 10:11:15
554
6
原创 Linux多线程编程的艺术:封装线程、锁、条件变量和信号量的工程实践
pthread_create函数要求传入一个void *(*start_routine) (void *)类型的函数指针,但为了可以让用户更灵活的使用,我们可以在这里进行一下封装。也就是说希望用户想传什么类型的函数指针都行,那么可以单独设计这样一个函数,如下:
2025-03-31 10:28:30
907
47
原创 高并发内存池(一):项目介绍和Thread Cache实现
在多线程环境下进行内存申请本质上属于对公共资源的访问,高并发场景下对内存分配锁的竞争会异常激烈,这将严重拖慢程序运行效率。此外,频繁的系统级内存申请不仅会产生额外开销,还可能引发内存碎片问题。传统的malloc内存分配机制由于这些固有缺陷,已难以满足现代高性能开发中对内存管理效率的需求。
2025-03-28 10:04:43
1216
62
原创 定长内存池原理及实现
所谓“池化技术”,就是,以备不时之需。之所以要申请过量的资源,是因为每次申请该资源都有较⼤的开销,不如提前申请好了,这样使⽤时就会变得⾮常快捷,⼤⼤提⾼程序运⾏效率。在计算机中,有很多使⽤“池”这种技术的地⽅,除了。以服务器上的线程池为例,它的主要思想是:先启动若⼲数量的线程,让它们处于睡眠状态,当接收到客户端的请求时,唤醒池中某个睡眠的线程,让它来处理客户端的请求,当处理完这个请求,线程⼜进⼊睡眠状态。
2025-03-25 10:48:33
995
66
原创 Linux信号的诞生与归宿:内核如何管理信号的生成、阻塞和递达?
在我们运行程序时通常会用Ctrl+c来使程序退出,这其实是向前台程序发送2号信号。除此之外还有Ctrl+\,表示发送3号信号,同样是让程序退出,2号信号与3号信号的区别将在下文核心转储部分详细讲解。
2025-03-21 09:41:06
12715
79
原创 操作系统的心脏节拍:CPU中断如何驱动内核运转?
当以上程序执行到scanf时,如果我们不输入信息,程序会一直阻塞在这里。那程序如何知道我们已经完成输入了呢?而且我们输入的信息在外设上,程序又是如何知道何时将其载入内存的呢?这其实是由外设就绪后通知给CPU,再由CPU通知给操作系统,然后由操作系统调用最后通知给前台程序。具体细节如下:每个中断都有自己的编号,即中断号,在中断控制器中会有寄存器来记录已就绪的中断号。一旦有外设就绪,它的中断号将被存入寄存器,然后由中断控制器通知CPU。
2025-03-18 10:42:08
1244
61
原创 共享内存通信效率碾压管道?System V IPC原理与性能实测
共享内存是通过在物理内存上开辟一块空间,然后让需要通信的进程都映射到这一块空间,这样就使它们看到同一块资源了。 共享内存通信是双向的,也就是说一个进程可以即读又写,而且使用起来就和c语言申请的malloc差不多。这种通信方式存在着数据安全问题,会在下文细说。 创建共享内存使用shmget函数,它的作用是创建或获取共享内存段的系统调用。 对于shmget用起来还是挺简单的,但是要把它的各种参数的设定都理解还是很困难的,接下来我会进行详细讲解。 问题2很
2025-03-12 10:08:08
930
72
原创 子数组问题——动态规划
用动态规划做子数组类的题时,对于状态表示我们可以直接设:dp[i]为以i元素结尾的子数组的... ... 后面就根据具体的题目要求填写,可能是子数组的和或者子数组的积等等,无论如何都可以以i元素结尾的子数组为研究对象去思考问题,如果解决不了就尝试增加状态,但研究对象不要改变。如果还解决不了那么再考虑改变或增加研究对象。
2025-03-06 10:17:42
7136
56
原创 多状态dp——动态规划
每个状态点需要维护多个子状态,分别表示不同情境下的最优解。例如,股票买卖问题中,每个时间点需记录「持有股票」和「未持有股票」两种状态下的最大收益。:将问题划分为多个互相影响的状态。例如:股票问题:持有、未持有、冷冻期。粉刷房子:当前房子涂红、蓝、绿时的最小成本。:每个子状态的值需根据前一步其他子状态计算。例如:当天持有股票的最大收益 = max(前一天已持有继续持有, 前一天未持有当天买入)。
2025-02-26 10:08:29
1145
45
原创 基础dp——动态规划
动态规划(Dynamic Programming,简称dp)是一种通过将复杂问题分解为更小的子问题来解决的算法思想,尤其适用于具有重叠子问题和最优子结构的优化问题。其核心目标是避免重复计算,通过存储中间结果(记忆化)来提升效率。动态规划 vs 分治法共同点:都将问题分解为子问题。区别分治法(如归并排序)的子问题独立,无重叠,无需存储中间结果。动态规划的子问题有重叠,需存储中间结果避免重复计算。
2025-02-23 08:26:44
2225
46
原创 FloodFill算法——搜索算法
FloodFill算法字面意思就是洪水灌溉法,比如我们有这么一块地:0表示平原,正数表示高地,负数表示凹地,那么当洪水来临时这些凹地会被优先灌满。而我们要找的正是这些联通块,如:它是一种暴力搜索的思想,只要我们把每个地方都搜索一遍,那么最终的结果必定会水落石出。通常可以使用BFS、DFS或并查集解决。接下来我们直接从题中感受。
2025-02-13 10:01:36
947
41
原创 DFS+回溯+剪枝(深度优先搜索)——搜索算法
递归是这样理解把它拆分出来,两个字,递和归递递推这就需要找到递推公式归回归需要找到回归条件,递推过程逐渐逼近回归条件直白一点来说就是,一个函数自己调用自己的情况,当然一定是要能够返回的。二叉树的遍历,快排,归并中都用到了递归。
2025-02-10 10:03:35
1672
36
原创 BFS(广度优先搜索)——搜索算法
BFS,也就是广度(宽度)优先搜索,二叉树的层序遍历就是一个BFS的过程。而前、中、后序遍历则是DFS(深度优先搜索)。从字面意思也很好理解,DFS就是一条路走到黑,BFS则是一层一层地展开。
2025-02-03 10:14:43
2499
58
原创 进程池的制作(linux进程间通信,匿名管道... ...)
在程序使用内存的时候,比如vector扩容机制,会提前给你开辟一块空间供你使用,尽管现在用不到,相当于做一下预备。因为只是一个小测试,代码写的并不严谨(没有检查调用是否成功,没有关闭文件,没有进程等待)大家不用太在意,能说明问题就行。,但它与一般的文件还是有些区别,文件都是储存到磁盘上的,而进程之间通信用的文件并不需要把它储存到磁盘上,它只是作为一个传输介质。那么进程池也同样,给父进程提前开辟一些子进程,提供父进程使用。,顾名思义就是没有名字,也不需要名字,因为子进程能够继承下来父进程开辟的管道资源。
2025-01-27 09:00:33
1381
33
原创 动静态库的制作与使用(Linux操作系统)
首先准备好需要做成库的源文件与头文件,如下示例:注意:在制作库方法过程中不能有main函数。如果代码使用c语言进行写的,执行以下语句把所有.c文件进行编译得到了.o文件。gcc -c *.c使用ar指令把所有.o文件链接成静态库,如下:-r(replace):此选项表示在插入文件到库时,若遇到同名的成员,则进行替换。它确保了库中的文件是最新的。-c(create):这个选项用于创建一个新的库文件。如果指定的库文件已经存在,它并不会被覆盖,而是会报错提示文件已存在。
2025-01-23 10:15:58
1055
49
原创 深入理解Linux系统内存中文件结构以及缓冲区,模拟实现c语言库文件接口
当语言层缓冲区刷新之后,数据并不会马上写入磁盘,而是放到了系统的缓冲区,系统缓冲区的作用是减少磁盘的随机读写,增加顺序读写从而提高读写效率。因为读写到一起的都是相关性强的数据,等再次被读的时候就可以一起被读出来。
2025-01-20 09:25:31
1637
38
原创 分治算法——优选算法
本章我们要学习的是分治算法,顾名思义就是分而治之,把大问题分为多个相同的子问题进行处理,其中我们熟知的快速排序和归并排序用的就是分治算法,所以我们需要重新回顾一下这两个排序。
2025-01-09 09:15:48
1876
58
原创 自制shell命令行解释器,深入理解Linux系统命令行实现原理
环境变量表需要我们在程序启动时就将它导入, 当然程序启动后环境变量默认是父进程的,所以我们可以重新开辟空间把原环境变量的数据拷贝过来,然后再把environ更新为新的地址。具体实现请参考下文源码。
2024-12-09 09:13:31
1238
75
原创 深入理解进程的退出、等待与替换(Linux系统)
进程等待指的是父进程等待子进程结束。在子进程结束后它的pcb不会立马释放,而是进入僵尸状态,让父进程回收。当然如果父进程永远不来回收,那么子进程pcb就永远得不到释放,从而内存泄漏。而父进程在等待子进程退出这个过程就叫作进程等待。
2024-12-07 09:53:23
1253
54
原创 虚拟地址空间与物理内存(Linux系统)
在虚拟内存与物理内存之间存在着一个媒介,它就是页表,起到一个交通枢纽的作用,它实际上是一个映射关系,把虚拟内存上的值通过页表映射得到对应的物理内存。当然页表的作用不止于此,它还起到权限管理的作用,即每个地址都用自己的rwx权限,对野指针、空指针等进行访问,就是在页表这里被拦截的。
2024-11-27 09:28:32
1803
85
原创 操作系统的理解
要理解这个结构,我们需要就盯着数据流动这条线来分析,很容易发现CPU是只与存储器打交道,而不与输入输出设备直接接触,这里存储器起到一个交通枢纽的作用。那么为什么会有这种结构呢,为什么不是“输入”—>“CPU处理”—>“输出”呢?
2024-11-22 09:16:19
812
77
原创 智能指针原理、使用和实现——C++11新特性(三)
智能指针简称RAll,是一种自动化管理资源的类模板,这里指的资源可以是:动态开辟的内存,文件指针,网络连接,互斥锁等等。RAII在获取资源时把资源委托给⼀个对象,接着控制对资源的访问,利用对象的⽣命周期结束时会自动析构的特性来完成对资源的自动释放,这样保障了资源的正常释放,避免资源泄漏问题。
2024-11-18 10:15:20
832
74
原创 C++11新特性(二)
C++11⽀持可变参数模板,也就是说⽀持可变数量参数的函数模板和类模板,可变数⽬的参数被称为参数包,存在两种参数包:模板参数包,表⽰零或多个模板参数;函数参数包:表⽰零或多个函数参数。
2024-11-12 12:35:21
916
69
原创 右值引用——C++11新特性(一)
右值引用在引用右值的时候实际上是把该右值的资源的地址保存。而该资源不会被立即释放掉,相当于延长了生命周期,因为右值都是一些临时对象、常量、匿名对象等这些“将亡”值。反正这些资源又没有人使用,那么就不急着释放它可以让右值引用接管它。
2024-11-11 08:44:29
677
57
原创 Linux开发工具——make/Makefile
Makefile是一种自动化构建工具,make是一条指令,Makefile是一个文件,当我们创建名为Makefile的文件后在Makefile中按照一定的规则制定一些命令。然后我们在命令行输入make命令后会自动执行Makefile文件中的指令。
2024-11-06 09:02:19
1233
65
原创 Linux权限
linux中的用户有两种,root用户(超级管理员)和普通用户,root的权限是最高的。而普通用户的权限比较低,在做某些操作时需要使用sudo命令来短暂提权。但是并不是任何用户都能够提权,如果任何用户都能提权那么root和普通用户就没有权限区分的意义了,而要能够使用sudo提权这个普通用户必须在root的“白名单”里。
2024-11-01 09:40:43
1193
79
原创 哈希表——unordered_set和unordered_map的封装
哈希函数:就是让数据与储存位置建立一种映射关系,通过这种映射关系就能够快速找到某个数据储存的位置。哈希冲突:不同的数据可能会映射到同一块区域,那么先储存的数据存到了该位置,后储存的数据的位置就被占用了,这两个数据产生哈希冲突。
2024-10-28 12:05:31
3275
76
原创 位运算——优选算法
按位与:&两者为真(1)才为真(1),也可以理解为只要有假(0)就一定为假(0),如下:按位或:|只要有一个是真(1)则为真(1),否则为假(0)按位异或:^相同为假(0),相异为真(1),如下:1==异或(^)运算规律:对任意常数a,b,c有:按位取反:~真(1)变为假(0),假(0)变为真(1),如下:位运算的优先级关于位运算的优先级是一个让人很头疼的事情,不过也很好解决,直接简单粗暴多加括号就行,就像写宏定义一样。
2024-10-23 13:08:15
3082
75
原创 红黑树的理解与实现(详解)
红黑树规则(重点!红黑树的性质都由以上4点规则决定的,其中的一个性质:红黑树最长路径的节点数量一定不会大于最短路径的两倍。这使得红黑树虽然不是完全平衡但高度差没有那么大,查找效率依旧是longN级别的。红黑树为什么能实现最长路径不会超过最短路径的两倍呢?我们可以想一想如果其中任意一条路径有n个黑节点,最短路径的颜色是然后分布,最长路径颜色又是然后分布的呢?其实很简单根据第4条规则我们可以最短的路径的节点不可能低于n个,(即最少的时候为n个黑节点)。
2024-10-19 11:17:16
954
83
原创 前缀和算法——优选算法
前缀和是指从数组的起始位置到某一位置(或矩阵的某个区域)的所有元素的和。这种算法通过预处理数组或矩阵,计算出每个位置(或区域)的前缀和,并将其存储在一个额外的数组或矩阵中,以便在后续查询中可以快速获取任意区间(或区域)的和。对于一维数组,可以使用递推公式来计算前缀和;对于二维矩阵,可以使用类似的递推公式,但需要考虑更多的边界情况。接下来我会用两个题来详细讲解前缀和的使用。
2024-10-11 12:03:02
2515
91
原创 AVL树的创建与检测
什么是AVL树?其实它就是一颗平衡的二叉搜索树,我们都知道一颗二叉搜索树在极端情况下会退化为单支(和链表同样的结构),那么它的查找效率就会变为O(N),AVL树的就是通过一些操作来防止这种退化,从而使查找效率保持在O(logN)。对一个AVL树操作的时候首先就是需要知道它是否平衡,所以可以在节点上多增加一个变量用来储存左右子树的高度差,这个数据我们就称之为平衡因子。(即平衡因子=左子树的高度-右子树的高度)平衡因子只是起到一个辅助的作用,也可用其他方式。
2024-10-05 11:09:59
1048
88
原创 set和map结构的使用
如果快指针与慢指针相遇,则有环并记录相遇点,找两个速度相同的指针一个从头开始走,一个从相遇点开始走,那么它们相遇时的点就为环的入口点。方法二:使用一个指针从链表的头走到尾,并且使用一个set容器,每走一步判断set中是否已存入该值,如果没有则存入,如果有那么这个链表一定有环并且该点就是环的入口点,直接返回该值即可。map和set的区别:set一块区域只储存一个关键字(记为key),而map储存的是一个key和value,key和value是一个映射关系,通过key可以找到对应的vaule。
2024-09-28 09:16:52
1224
86
原创 多态的使用和原理(c++详解)
多态顾名思义就是多种形态,它分为编译时的多态(静态多态)和运行时的多态(动态多态),编译时多态(静态多态)就是函数重载,模板等,通过不同的参数来完成对不同的函数的调用(即生成多种形态)并且这个过程在编译阶段就已经完成。动态多态是在运行时根据对象的实际类型来确定调用函数的哪个版本,完成不同的⾏为。
2024-09-20 19:16:47
1723
80
原创 二分算法——优选算法
1、二分算法并不局限于数组有序,在要找到数据的二段性即可使用二分算法。2、二分算法模板2.1.朴素二分模板else ...2.2.左边界查找模板2.3.右边界查找模板。
2024-09-16 09:43:19
1726
104
原创 滑动窗口——优选算法
相对于暴力解法而言滑动窗口本质其实是减少不必要的枚举,那么当我们做题时一眼看不出可以使用滑动窗口或者知道要使用滑动窗口但不知道如何用的时候,我们就可以从暴力枚举的角度出发,从暴力中的寻找规律并优化。
2024-09-09 11:16:45
1933
111
原创 双指针——优选算法
1、以上三道题分别对应数组划分、数据的单调性、数据的循环,在以后涉及这种类型题的时候都可以从双指针方向去考虑。2、对于能使用暴力枚举解决的问题也可以考虑使用双指针去降低时间复杂度提高效率。3、通常所说的双指针算法只是一种思想并不是用真的使用指针。
2024-09-02 09:12:52
1742
113
原创 priority_queue模拟
priority_queue是C++标准库中的一个容器适配器,用于实现优先队列(priority queue)的数据结构。优先队列是一种特殊的队列,其中的元素按照一定的优先级进行排序,每次取出的元素都是优先级最高的。它的优先级是可以通过传入参数自己调整的,它的底层实现通常使用堆(heap)数据结构。主要特点元素有序:队列中的元素会根据其优先级进行排序,优先级最高的元素总是位于队列的头部(或称为队首)。
2024-08-29 07:20:53
1168
96
原创 二叉树的分层遍历、栈的压入弹出序列
本章主要来讲解两个OJ题,针对每个OJ题我分三部分来解决,分别是题目解析(主要弄清楚题目要求我们解决什么问题),算法原理,代码编写,接下来让我们进入正题。
2024-08-24 16:25:41
894
83
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人