- 博客(89)
- 收藏
- 关注

原创 【项目设计】->高并发内存池(谷歌开源项目简化版)
高并发内存池,原型是谷歌(Google)的一个开源项目tcmalloc(Thread-Cache Malloc),线程缓存的malloc,目的是为了实现高效的多线程的内存管理。可以说是malloc和free在特定场景下的升级版。这个技术是非常有名的,go语言的内存分配器用的就是tcmalloc。使用场景:多线程应用,高性能服务器等。我在这里实现的并不是完全实现,而是把tcmalloc的核心框架进行简化后的实现,就是一个简易版,只是为了学习tcmalloc的精华。
2024-12-05 15:41:21
1331
原创 Linux练级宝典->线程安全
我们打印时,是打印的一个内存的值,在我们判断ticket<0时可能当前线程的内存的值是够的,但是突然切换线程,那个线程减到为0后此时切换回原来的线程,此时线程不知道,但是还是进行了--,此时继续更新ticket为-1.别的已经进入判断的线程也不知道,所以出现了负数。对于234而言,认为1的整个操作过程是原子的。1.我们把每个线程的寄存器al的值全都置为0,然后因为此时mutex的值为1,此时交换(这条指令是一条指令所以是原子的),此时有一个线程获取到锁了,其他线程看到的mutex还为0.就继续等待。
2025-03-17 12:33:01
1131
原创 Linux练级->信号量
3.信号量:可以更细致的划分被锁划定的临界资源,就像在锁住的临界资源里不同的区域又被上了锁,如果不同执行流要访问不同的临界资源区域,此时使用信号量就不会出现数据不一致情况。我们唯一会出现线程不安全的情况就是,二者在同一个位置的时候。如果套圈,只有两种情况,生产者把容器生产满了,此时消费者还没进行消费,另一种就是消费者消费特别快,已经没有数据了,此时生产者还没生产。第一种情况,生产者生产满了,追到消费者,此时生产者就不能动了,必须等待消费者消费后才能生产,不然就会把之前生产的数据给覆盖了。
2025-03-16 13:06:15
567
原创 Linux练级宝典->生产者消费者模型
如上图: 我们生产者生成数据丢进容器中,而消费者之间从容器中拿就好了,就像一个超市,生产者就是批发商,超市进货后就丢在里面了,而消费者就是我们买东西的人了。1.两个条件变量,一个给消费者用一个给生产者用,满了生产者就等待消费者消费,空了消费者就等生产者生产,所以在push 和 pop中都会唤醒对应的进程。相反如果是消费者消费的比较快,那此时就是步调一致的,因为生产者生产的慢,此时queue中没有数据,所以消费者只能等生产者生产一个消费一个。1.当队列为空时,获取元素的操作会被阻塞,直到队列中有元素。
2025-03-16 13:05:52
566
原创 Linux练级宝典->多线程
在一个程序里的一个执行流叫做线程(thread),线程是“一个进程内部的控制序列”。一切进程都至少有一个线程线程在进程内部运行,本质是在进程地址空间中运行。在Linux系统中,CPU眼中,看到的PCB都要比传统的更轻量通过进程地址虚拟空间,可以看到进程的资源,这样通过虚拟地址就可以把每个进程资源合理的分给每个线程,形成线程执行流我们知道一个进程(PCB)都有进程控制块(task_struct),进程地址空间(mm_struct)以及页表的建立,虚拟地址和物理地址就是通过页表进行映射的。
2025-03-15 07:22:34
1036
原创 Linux练级宝典->进程信号
CPU有一堆寄存器,寄存器中一部分是用来计算的,就比如两个数的计算就是先用两个寄存器把两个数存起来,算出结果后写回寄存器中,除了用来计算外,CPU中还存在一个状态的寄存器,用来标记当前指令执行结果的状态信息,有无进位,有无溢出等等。因为MMU是一种硬件单元,所以就有对应的状态信息,当我们寻找的虚拟地址并没有对应的物理地址说明查找的不属于自己的地址(野指针),此时出现错误,将自己的错误写到自己的状态信息中,然后就可以被操作系统识别到,进而给相对应的进程发送SIGSEGV信号。下图是status的低16位。
2025-03-15 07:21:59
722
原创 Linux练级宝典->任务管理和守护进程
每个进程除了进程ID以外,还有一个进程组,进程组就是一个或多个进程的集合同一个进程组,代表着他们是共同作业的,可以接收同一个终端的各种信号,进程组也有其唯一的进程组号。还有一个组长进程,组长进程ID == 进程组ID。组长进程可以创建一个进程组,创建进程,然后终止。:进程组只要还有进程就会存在,和组长进程无关,组长会易主。
2025-03-13 14:56:16
1106
原创 Linux练级宝典->进程间通信
进程间通信简称IPC(interprocess communication),进程间通信就是在不同进程之间传播或交换信息。
2025-03-13 14:55:23
1073
原创 Linux练级宝典->动态库和静态库
我们知道可执行文件前的4步骤 预编译->编译->汇编->链接例如,我们上面用5个文件组合出了可执行文件。.0文件就是汇编后的文件。我们在最后一步的时候不链接,而是把这些.o文件打包,这样的一堆.o文件组合到一起就是一个库了。
2025-03-12 12:31:51
1186
原创 Linux练级宝典->基础IO
我们知道系统在传输数据时是有缓冲区的,这里我们write用的就是系统层面的缓冲区,而另外两个C语言的接口,用的就是C语言的应用层的接口,本来我们的数据打印到显示器采用的是行缓存的策略,然后我们要打印到log.txt就变成了全缓冲,此时就导致我们的数据就一直保存到缓冲区中,然后子进程也过来了,此时两个进程用的同一个缓冲区,在函数结束时,因为二者要改变缓冲区的数据(输出)此时就发生写时拷贝,所以子进程和父进程都打印了一份。可以发现我们屏幕先打印了标准错误的内容,之后在文件中的内容是标准输出的。
2025-03-12 12:29:57
675
原创 Linux练级宝典-> 软硬链接
第一排就是他的inode号,我们看到软连接和原文件并不是一个文件,因为inode号不同,而且文件大小也不同,可以看见我们软连接文件特别小只有9字节。对应硬链接来说,和软连接不同,软连接是图标,而硬链接就是原文件的别名,此时二者都代表了这个文件,我们之前软连接删除原文件后,软连接失效,我们可以看看硬链接的结果。就是windows上的快捷图标,这个图标也是一个文件,而且可以通过这个图标直接打开程序这里也是同理:我们生成一个可执行文件并给他生成一个软连接文件试试。1.软连接是一个独立的文件,就是一个图标的意思。
2025-03-11 10:37:58
288
原创 Linux练级宝典->进程控制详解(进程替换,fork函数)
WNOHANG:设置以后,本来就是子进程不退出,父进程就一直卡着不动,如果设置了子进程没返回,那就先返回0给父进程,此时给父进程在一个循环里持续获取子进程退出信息,再循环体里父进程就可以继续做自己的事情。我们子进程和父进程是共享一块空间的,为什么不直接给子进程创建新的空间,如果父子进程只有读操作,重新开辟空间copy一份父进程的变量给子进程不是浪费吗?pid,进程地址空间,页表都没变,只有代码和数据变了。当然,这里的整个 子进程的代码数据都变了,所以和父进程就发生了写时拷贝,此时就不会影响父进程的数据了。
2025-03-11 10:35:38
760
原创 Linux练级宝典->Linux环境变量 ,main函数参数的意义
1.环境变量就是可以让系统直接找到指定程序的一个变量。2.这个变量在整个系统就像是一个全局变量。方便每一个程序都能获取3.main函数的三个参数的含义:1.选项个数。2.具体选项的字符指针数组。3.环境变量的字符数组。
2025-03-10 16:11:21
1040
原创 Linux练级宝典->Linux进程概念介绍
这个分裂的进程,也会被创建出来,所以此时就是两个进程,那代码怎么执行的,当然就是共用一份代码,后面会有进程替换(exec),把子进程的执行逻辑脱离出去执行另一个程序,父进程依旧执行老代码。2.所以使用虚拟空间,实际就是在你时间片期间用多少就给你多少,并且通过映射的规则,我们在上层就不用担心,不同的进程的数据被修改了,因为这是操作系统进行维护的。什么是进程优先级,首先我们知道,我们假设了PCB的管理是一个链表,那除了按顺序取走进程外,如果有突发事件,或者优先级高的任务,此时就有了进程优先级的概念。
2025-03-10 16:10:15
1193
原创 Linux练级宝典->Linux进程状态详解,孤儿进程,僵尸进程
先看一张大图,可以看到我们在进入CPU之前,我们的进程是有很多状态的。这个代码是Linux进程状态的全部种类我们知道Linux的PCB进程控制块叫做task_struct.里面中就有一个变量就是存储这个状态的。要怎么查看呢?我们查看进程的详细信息是通过一个指令 ps + 选项的。ps auxps ajx都可以看到对应的进程状态,下面就对进程状态进行详细解释。
2025-02-23 13:00:42
949
原创 网络练级宝典-> TCP协议
检验和。序列号。确认应答。超时重传。连接管理。流量控制。拥塞控制。滑动窗口。快速重传。延迟应答。捎带应答。TCP定时器TCP中还设置了各种定时器。重传定时器:为了控制丢失的报文段或丢弃的报文段,也就是对报文段确认的等待时间。坚持定时器:专门为对方零窗口通知而设立的,也就是向对方发送窗口探测的时间间隔保活定时器:为了检查空闲连接的存在状态,也就是向对方发送探查报文的时间间隔。TIME_WAIT定时器:双方在四次挥手后,主动断开连接的一方需要等待的时长。
2025-02-23 12:59:57
945
原创 网络练级宝典-> UDP传输层协议
我们知道端口号对应的其实就是一个进程的pid,在操作系统中二者的对应关系用的是hash进行存储的。即我们可以通过端口号找到对应的进程。而对于我们的服务器来说,在接收到发送端的数据时,这时要传给哪个应用(进程)是通过端口号来确认的这个工作就是传输层要做的事:把数据交给应用层,和从应用层中获取数据传出(封装报头)怎么标识一个通信源IP地址,目标IP地址,源端口号,和目标端口号,协议号。这5个号来标识一个信息的来去地方。
2024-12-04 15:31:58
1074
1
原创 C++11练级宝典->包装器详解 function 和 bind介绍
/ 函数名// 函数对象// lamber表达式function<函数返回值(函数参数)> 包装器的名字 = 可调用对象此时封装好的f1 f2 f3就是一个类型了。
2024-11-30 08:07:12
716
原创 C++11练级宝典-> 智能指针详解 (4种智能指针)
这里默认大家都知道线程了,这里会出现线程竞争的地方就是我们的_pcount,这个问题在单线程时没有,多线程时这个变量应该是共用的,当多个线程都是指向同一块空间,此时同时调用这个_pcount变量,就出现线程竞争问题了。我们上述实现的所有只能指针都是用delete释放的,但是对于数组delete[],是没有办法的,还有文件的fclose这类不是调用delete关闭的接口,再用delete就不礼貌了。所以不管怎么复制都是一样的值(一样的地址),所以使用指针当计数器是最好的。顾名思义:分享的指针。
2024-11-30 08:06:50
1064
原创 C++11练级计划->《可变模版参数》C++11强大特性之一
可变参数模版:返回类型 函数名(Args… args)//函数体原本的参数模版:返回类型 函数名(T t)//函数体定义时,...在前,Args这个名字不是固定的,所以其实和原来不一样的地方是+了3个.在使用时 ...在后,args这个名字也是不固定的。ShowList(1, 'A', string("hello"),2.03,"自律aron");return 0;如上代码:此时我们就可以随便传入参数进去了。
2024-11-29 13:27:28
1111
原创 C++练级计划->《右值引用和移动语义》
左值是一个有具体地址的值。左值可以被取地址。左值既可以在赋值符号左边也可以在右边。int main()//以下的p、b、c、*p都是左值int b = 1;int d = c;//左值左右都在return 0;右值不可以取地址,且不能被更改右值只能出现在右边,只能是赋值的那个int main()//以下几个都是常见的右值10;x + y;fmin(x, y);//错误示例(右值不能出现在赋值符号的左边)//10 = 1;return 0;
2024-11-29 13:26:49
989
原创 C++11练级计划->《lambda表达式》速成
先介绍一下:我们在算法题需要使用sort函数时,会发现除了指定范围以外,还有一个默认的模版参数可以填,这个就是sort用来排序的比较函数。lambda函数就是一个匿名函数;用完就丢的。
2024-11-28 11:58:41
693
原创 C++练级计划->《hash哈希冲突》
我们底层的hashtable其实是类似vector的,所以查找很快,但是怎么存才是关键通常来说如果要存的key是int等整数类型,通过hash函数转换为下标(用取模来限制范围)存储,如果是key是类似string等类型,那就需要对应的新的方法来把string转换为下标然后进行存储。所以哈希函数的作用是,将键转换为一个整数,这个整数通常称为哈希值(Hash Value)。哈希表的范围通常与哈希表的大小相同。当我们插入或查找数据时,首先计算键的哈希值,然后根据哈希值在哈希表中定位数据。
2024-11-27 14:31:45
606
原创 C++练级计划->《hash哈希使用详解》
方式一: 构造一个某类型的空容器。//构造int类型的空容器方式二: 拷贝构造某同类型容器的复制品。//拷贝构造同类型容器us1的复制品方式三: 使用迭代器拷贝构造某一段内容。//构造string对象某段区间的复制前两个没什么好说的,都是正常的构造函数,方式三采用迭代器构造,就是通过迭代器遍历对象的元素然后把元素一个一个的放入unordered_set中方式一: 指定key和value的类型构造一个空容器。//构造一个key为int类型,value为double类型的空容器。
2024-11-27 14:31:26
852
原创 C++练级计划->《单例模式》懒汉和饿汉
很显然我们要实现单例,那就不允许你在类外调用构造函数,生成这个对象,所以我们在类内就声明了这个对象,初始化时也是只能对这个对象(_slt)初始化。这时候就需要一个日志记录器,用于记录所有模块的日志信息,所以这个记录器应该是针对所有人的,并且为了避免重复,所以使用单例模式。在多线程下的线程安全对象。顾名思义:饿汉,就是一个很饿的人,只要有东西吃立马就吃了,没有任何等待的所以饿汉模式就是在还没进入main函数前就实例好的模式。顾名思义:懒汉,就是很懒的一个人,顶级拖延症,只有必要时才会做对应的事,所以。
2024-11-26 14:58:43
760
原创 C++练级计划->《多态》虚函数表,菱形继承多态
现实中买票的测策略:学生 社会人 军人都是要买票的,但是不同的人买票买到的价格却可能是不一样的,学生票,普通票,军人票。虽然我们都执行了买票的操作,但是我们的操作行为是不一样的。多态其实是一种语法特性,只有你使用时他才会出现,不使用时,这个特性不会出现如下是多态形成的条件。
2024-11-26 14:58:15
1580
原创 C++算法练级计划->《环形链表》(看完包会)
k*(x + y),这个k是不确定的,如果环很小,那在slow入环时fast可能已经跑很多圈了。然后我们这时重新定义指针红指针为(从head出发的一个slow速度的指针),slow指针(蓝指针)依然在C点。因为本来fast距离跑完一圈是y,此时过了y个时间所以fast跑完一圈应该还多跑了y的距离,而此时slow也是刚跑出y的距离,所以二者相遇。先不要想其他的,想过了y个单位时间,此时slow应该走过了y的距离,而fast应该走过了2y的距离。设slow入环时,fast的路程为Sb,slow的路程为Sa;
2024-11-25 08:25:20
611
原创 C++练级计划->《模版》分支特化
目录不传类型传整数效果如下:函数模版特化(类似重载)类模板的特化全特化:偏特化:偏特化还有一个特殊的形式:指针和引用模版建议不要分离声明定义原因:编译时不实例化出错解决方法1:在定义处,将函数实例化(麻烦不推荐)2:对于模版直接不用分离声明和定义(推荐)不传类型传整数前面我们的模版都是传入类型后自动生成对应类型的类或者函数,但是C++有非类型模版参数,顾名思义:不是传入类型的模版参数。template<class T, size
2024-11-24 09:15:46
876
原创 C++练级计划 -> 《模版》泛型编程
T _Chinese;T _English;//类模板中的成员函数在类外定义,需要加模板参数列表//上面就是模版头,只有声明与定义分离时使用,如果在类内定义就不需要了cout << "数学:" << _Math << endl;cout << "语文:" << _Chinese << endl;cout << "英语:" << _English << endl;
2024-11-24 09:14:16
658
原创 C语言练级->##__VA_ARGS__(可变参数)的用法
这个##将逗号和__VA_ARGS__拼接起来,结果__VA_ARGS__此时为空,和逗号拼接后相当于逗号被拿走了,如果平时有可变参数传入时,这时就算拼接了,那也是正常显示逗号,所以没问题。首先##和__VA_ARGS__其实是没什么关联的,##有单独的语法说明,__VA_ARGS__也只是一个宏参数。由上可知:__VA_ARGS__和...的分工是明确的,一个是在定义使用,一个是在宏体内使用。通常__VA_ARGS__用于宏定义,其中关于日志宏需要用的,printf 等支持可变参数的函数的宏封装。
2024-11-23 14:05:17
834
原创 C++练级计划->《海量数据处理》面试题
海量数据:顾名思义:数据量很大,正常的方法例如哈希无法装下这么多数据时,要使用别的结构来解决下面是三种海量处理思想:有三个问题,深度层层递增。
2024-11-23 14:04:36
795
原创 priority_queue优先级队列(堆)详解。C++经验+1
priority_queue就是用vector 作为 模版,然后里面的数据填充的方法用的是堆算法。所以priority_queue就是堆。只不过是提供了对应接口的堆。不用手动去敲。方法一:默认定义(只指定是什么元素)默认定义:造出来的直接就是一个大顶堆。方法二:定义大顶堆(指定元素以及用什么当模版以及比较函数)上面不是说priority_queue用vector做模版吗?为什么这里我们还要写一遍。
2024-09-25 17:49:30
778
原创 二叉搜索树(来学包会) C++经验+1
二叉树都知道,二叉搜索树就是:每个节点的左子树的值全都小于当前节点的值,右子树的值全都大于当前节点的值。要这个树有什么用?1.二叉搜索树的中序遍历是有序的。2.顾名思义就是为了搜索,线性遍历搜索一个值是全部走一遍,而对于二叉搜索树而言,每走一次就能排除一半的结果。所以就是快。当然也会出现一些特例,如下图所示如果一开始插入的数比后面的数都大,那就变成了一串的。如果这样来搜索,和线性遍历也没区别了,所以后面开发出了AVL树和红黑树解决。注意:二叉搜索树的值是不能被更改的!!!!
2024-09-25 17:49:10
1208
原创 C++内存管理
class Testpublic:Test() //构造函数:_a(0)cout << "构造函数" << endl;~Test() //析构函数cout << "析构函数" << endl;C++://申请delete p1;//销毁//申请free(p2);//销毁申请多个对象和申请内置类型同理。
2024-09-22 17:49:45
1038
原创 C++迭代器 iterator详解
它提供了一种访问容器(如列表、集合等)中元素的方法,而无需暴露容器的内部表示。迭代器使得程序员能够以统一的方式遍历不同的数据结构,而无需关心这些数据结构的具体实现细节。类似于指针指向对应的元素并且能对这个元素进行修改和使用。
2024-09-22 17:49:40
2757
原创 C++日期类详解 第二级支线任务
上述代码表示了这次要实现的类,包括了多种运算符的重载,以及构造函数,相似的操作符,我们只实现一个。日期类的析构和拷贝赋值函数不用写用默认的,因为日期类用的都是内置类型,没有动态开辟的空间,所以不用考虑深拷贝的问题。
2024-09-20 18:15:29
1038
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人