- 博客(51)
- 收藏
- 关注
原创 Linux——多线程(五)
thread.hppmain.cc此时会报错:无效使用非静态成员函数...主要原因是成员函数包含this指针而thread.hpp中线程所要执行函数的参数为空:using func_t = std::function;,导致参数类型不匹配有两种解决方法方法一:在Print函数前面加上static。
2024-07-10 02:59:31
651
1
原创 Linux——多线程(四)
这是之前基于阻塞队列的生产消费模型中Enqueue的代码缺点:当一个线程往阻塞队列中插入时,必须要满足一个条件"临界资源还没满",否则就需要放到条件变量的等待队列中去。而判断临界资源是否为满,然后再进入临界区访问临界资源,才能判断临界资源是否为满。那么只要我们对临界资源整体加锁,就默认会对这个临界资源整体使用(吗?实际上可能是:一份临界资源被划分为多个不同的区域,而且运行多个线程同时访问不同的区域。在访问临界资源之前,我们无法知道临界资源的情况。多个线程不能同时访问临界资源的不同区域。
2024-07-10 02:38:01
976
1
原创 Linux——进程间通信一(共享内存、管道、systrem V)
什么是管道?一个文件打开两次,那么在操作系统中会有2个struct file 但是这两个struct file指向同一个缓冲区若父进程3为读端,4为写端,子进程也一样。那么子进程写入,父进程读取缓冲区内容,这是父子进程看到了同一块资源。这种基于文件的,让不同进程看到同一份资源的通信方式叫做管道管道只能被设计成单向通信。
2024-07-06 23:17:57
1069
原创 Linux——多线程(三)
在上一篇博客中我们讲到了在加锁过程中,线程竞争锁是自由竞争的,竞争能力强的线程会导致其他线程抢不到锁,访问不了临界资源导致其他线程一直阻塞,造成其它线程的饥饿问题,想要解决此问题又涉及一个新概念。
2024-06-02 16:53:32
981
1
原创 Linux——多线程(二)
但是还有另外的问题:加锁,线程竞争锁是自由竞争的,竞争能力强的线程会导致其他线程抢不到锁,访问不了临界资源导致其他线程一直阻塞,造成其它线程的饥饿问题
2024-06-01 15:50:19
1001
原创 Linux——多线程(一)
教材中的概念: (有问题?线程是进程内部的一个执行分支,线程是CPU调度的基本单位之前我们讲的进程:加载到内存中的程序,叫做进程---(修正)---->进程=内核数据结构+进程代码和数据。
2024-05-28 22:50:01
1240
原创 Linux——进程信号(二)
在进程信号(一)中我们已经讲到了信号的保存,那么接下来要讲信号的处理了。信号的处理主要要回答3个问题:1.信号什么时候被处理的?2.信号如何被处理的?3.捕捉信号还有其他方式吗?首先回答问题一:信号在合适的时候被处理,那什么是合适的时候呢?这就要先看什么是内核态和用户态了。
2024-05-25 16:28:02
1156
1
原创 Linux——进程信号(一)
什么是信号?结合实际红绿灯、闹钟、游戏中的"!"等等这些都是信号。以红绿灯为例子:一看到红绿灯我们就知道:红灯停、绿灯行;我们不仅知道它是一个红绿灯而且知道当其出现不同的状况时我们应该做出怎么样的行为去应对。对于红绿灯:我们之前受过的教育,让我们能够识别这个红绿灯(即使它还未出现在我们眼前),也就是说你能识别"红绿灯"当绿灯量了后我们不一定要直接走,也可以等一会再走(也就是说接收信号后我们不一定要立刻产生对应的行为)当红灯亮了之后,我们可以玩手机,要记得这个时候还是红灯。
2024-05-23 20:06:21
1456
2
原创 Linux——基础IO2
之前在中我们讲的都是(进程打开的文件)被打开的文件那些未被打开的文件呢?大部分的文件都是没有被打开的文件,这些文件在哪保存?磁盘(SSD)OS要不要管理磁盘上的文件?(如何让OS快速定位一个文件)要(通过路径快速定位文件)
2024-05-05 21:16:37
1179
原创 Linux——基础IO(1)
铺垫:文件1.之前我们讲过文件=内容+属性磁盘中创建一个空文件也要占空间(就算内容为空,文件属性也占空间)文件操作=文件内容的操作+文件属性的操作有可能在操作文件的过程中既改变内容又改变属性2.访问文件之前,都得先打开文件修改文件是通过执行代码的方式完成修改,文件必须加载到内存之中(打开文件)——冯诺依曼体系决定:CPU只能从内存中对数据做读写3.是谁在打开文件?进程在打开文件(程序被执行,进程被调度,fopen打开文件)通常我们打开文件、访问文件、关闭文件都是进程在进行相关操作;
2024-05-05 12:45:53
925
原创 C++11——新特性(二)
前面我们列表初始化、变量类型推导、STL中的一些新变化,已经右值引用的移动语义。本篇博客将续上篇,继续介绍C++11的新内容并且补充上篇文章中一些没有介绍完的内容。右值引用引用左值及其一些更深入的使用场景分析、完美转发、模板的可变参数、lambda表达式、包装器等。
2024-04-09 00:03:21
846
原创 C++11——新特性(一)
但是当函数返回对象是一个局部变量,出了函数作用域就不存在了,就不能使用左值引用返回,只能传值返回。例如:bit::string to_string(int value)函数中可以看到,这里只能使用传值返回,传值返回会导致至少1次拷贝构造(如果是一些旧一点的编译器可能是两次拷贝构造)。
2024-04-05 23:42:46
928
原创 位图和布隆过滤器
有误判率,即存在假阳性(False Position),即不能准确判断元素是否在集合中(补救方法:再建立一个白名单,存储可能会误判的数据)
2024-04-04 17:46:14
653
原创 C++——哈希(二)unordered_map和unordered_set的封装
在中我们已经对闭散列的哈希表(线性探测法)和开散列的哈希表(哈希桶)进行了简单的模拟实现,由于是简单实现,功能简单、没有迭代器且不支持不同的类型(非泛型编程)。此时我们这篇文章主要是对上次开散列哈希表的完善并用其封装出unordered_map和unordered_set上次哈希桶的代码。
2024-04-02 20:59:26
947
原创 C++——哈希(一)
哈希冲突是无法避免的(在有限的空间中存无限的值,不论哈希函数多精妙,哈希冲突的结果是必然的),不过哈希函数设计得越精妙那么产生哈希冲突的可能性就越低
2024-04-01 21:38:47
868
原创 map和set(四)——map和set的封装
这明显不符合我们泛型编程的思路,如果按照这种写法,那么每传一次不同的模板参数,都要根据这个模板参数去实现一个新的比较大小的重载函数我们可以面对不同的调用(比如map和set),对其取出不同的值(map中pair里面的first,set中的K)然后再进行比较,具体的怎么取出不同的值可以在要调用红黑树的类中实现(map和set中)
2024-04-01 17:41:25
780
原创 map和set(三)——红黑树
enum(枚举)里存的是节点的颜色节点要有指向左节点、右节点、父节点的指针;节点存的值(数据)及节点的颜色RED,BLACK, _kv(kv){}初始化(构造)节点,三指针指向空;_kv(值or数据)取决于传的值,_col默认为红色为什么(插入)节点的颜色默认为红色呢?如果插入黑色节点就会破坏规则:每条路径上黑色节点的数量相同所以(插入)节点的默认颜色为红色2.2插入以下为简写:u uncle 叔叔p parent 父亲g grandfather 爷爷。
2024-03-25 20:55:52
952
原创 map和set(二)——AVL树的简单实现
和二叉搜索树类似,只不过多了个平衡因子//AVL树的节点//平衡因子//构造, _bf(0), _kv(kv){}
2024-03-10 20:19:37
965
原创 map和set(一)——关联式容器的常用接口使用及区别
set是按照一定次序存储元素的容器在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的。set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行 排序。set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对 子集进行直接迭代。set在底层是用二叉搜索树(红黑树)实现的。
2024-03-06 19:19:16
1074
原创 C++——多态
多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。比如Student继承了Person。Person对象买票全价,Student对象买票半价。那么在继承中要构成多态还有两个条件1. 必须通过基类的指针或者引用调用虚函数2. 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写重载两个函数在同一作用域函数名参数相同重写(覆盖)两个函数分别在基类和派生类的作用域函数名/参数/返回值类型必须都相同(协变除外)两个函数必须是虚函数重定义(隐藏)两个函数必须在基类和派生类的作用域。
2024-02-09 01:22:15
1005
原创 C++——stack与queue与容器适配器
1. 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的一个。2.此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)。3. 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的顶部。4. 底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。
2024-02-06 21:51:23
809
原创 Linux-3 进程概念(三)
进程地址空间是指每个进程在计算机内存中所占用的地址空间。地址空间是指能被访问的内存地址 范围,它由若干个连续的内存块组成。每个进程都有自己的地址空间,这意味着每个进程都有自己 的内存地址范围,不会与其他进程冲突系统给每个进程划分了很大的一块虚拟空间,所有的进程都认为自己会独占系统资源(实际上,这只是操作系统给进程画的饼)。等到进程真正申请的资源和空间的时候系统再到物理内存分配空间给进程既然进程地址空间是一张”饼“,那么”饼“要管理吗?OS要不要堆地址空间做管理呢?自然是要的怎么管理?先描述,再组织。
2024-02-05 15:04:10
1829
原创 Linux -3 进程概念(二)
进程不是一直在运行的,即便进程放在了CPU上,也不是一直会运行的它可能在等待某种软硬件资源,比如:当你的代码包含scanf函数,执行到此语句时进程在等键盘输入时间片:一个进程占用CPU资源(不管有没有跑完)固定时间(例:1ms)后会下来所谓的进程排队,一定在等待某种"资源"进程 = task_struct + 可执行程序注意:排队的是 task_struct一个task_struct可以被连入多种数据结构中,只不过这种连入和平常的连入不一样这样所有的数据结构就可以用同一套增删查改。
2024-02-04 21:49:44
708
原创 Linux-3进程概念(一)
冯·诺依曼结构,又称为普林斯顿结构,是一种将程序指令存储器和数据存储器合并在一起的存储器结构。程序指令存储地址和数据存储地址指向同一个存储器的不同物理位置,因此程序指令和数据的宽度相同,比如英特尔公司的8086中央处理器的程序指令和数据都是16位宽。数学家冯·诺依曼提出了计算机制造的三个基本原则,即采用二进制逻辑、程序存储执行以及计算机由五个部分组成(运算器、控制器、存储器、输入设备、输出设备),这套理论被称为冯·诺依曼体系结构。我们常见的计算机,如笔记本。
2024-02-04 14:50:27
788
原创 C++list的介绍和简单实现
list是一个双向带头循环链表该容器非常适合在任意位置插入和删除,时间复杂度都是O(1)与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
2024-01-29 17:47:10
664
原创 Vector简单实现
vector是表示可变大小数组的序列容器。就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。在我个人理解中,我把它看成一个数组,只不过可以存你所需要的各种内置类型或自定义类型迭代器相关容量相关shrink_to_fit是缩容访问元素修改元素。
2024-01-19 23:50:44
885
原创 string类的模拟实现
当然我这只是简单的实现一些常用的成员函数,毕竟库里string的成员函数这么多,全部实现也太肝了。=也要重载,后面会说)如果 n 大于当前字符串长度,则通过在末尾插入任意数量的字符来扩展当前内容,以达到。给缺省值的原因是初始化string类的时候不能让其为空值,当然'\0'和""都行。拷贝构造的不同之处就是在于它是基于同一个类所创建的不同对象而构造的对象。n一定要大于容量,你n小于或等于这个容量,我怎么扩,哪有越扩越小的道理。赋值可以是对象以及存在,只是把传过来对象拷贝到需要赋值的那个对象里去。
2024-01-04 14:27:14
866
1
原创 C++模板
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。swap函数面对多种类型,需要实现不同函数参数的swap,也就是写不同的swap函数。函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。类模板实例化的类:类名不是类型,类才是整个类的类型。假设st1是要存int,st2是要存double,那么就寄了。其次,代码的可维护性比较低,一个出错可能导致所有重载都出错。3、有合适的就用更合适的,哪怕自己做。
2023-12-18 23:27:46
741
原创 Linux项目自动化构建工具-make/Makefile
一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。1.makefile和make形成目标文件的时候默认是从上到下扫描makefile文件的,默认形成的是第一个目标文件。是通过对比最近修改时间,只要可执行程序的最近修改时间比所有源文件的最近修改时间新,说明它就是最新的。假如我们有一个.c文件,我们想要生成它的可执行程序,就需要依赖这个文件。如果先clean呢?
2023-12-05 22:51:39
356
原创 Linux权限
Linux有两种用户:1、root(超级管理员) 2、非root(普通用户)超级用户:可以再linux系统下做任何事情,不受限制普通用户:在linux下做有限的事情超级用户的命令提示符是“#”,而普通用户的命令提示符是“$”那么如何切换用户呢?可以用su命令su -切换成root用户(以root身份重新登陆一次)su (root)可省略(用户身份切换成root)
2023-11-13 18:11:07
83
原创 类和对象(中)
当一个类之中什么也没写时,里面真的什么东西都没有吗?当然不是,当你创建了一个类,编译会默认帮你生成这6个成员函数也就是说,就算你什么也没有写,类里面照样存在这些成员函数初始化和清理 构造函数主要完成初始化工作 析构函数主要完成清理工作拷贝复制 拷贝构造是使用同类型对象初始化创建对象 赋值重载主要是把一个对象赋值给另一个对象取地址重载 主要是普通对象和const对象取地址,这两个很少会自己实现。
2023-10-27 15:17:48
61
1
原创 类与对象(上)
/类体:由成员函数和成员变量组成class为定义类的关键字,ClassName为类的名字,{}中为类的主体(类体)注意类定义结束时后面分号不能省略类体中内容称为类中的变量称为类的属性或成员变量;类中的函数称为类的方法或者成员函数类的定义有两种方式1.声明和定义都在类体内//1.声明和定义都在类体内class Date//成员变量int _year;int _month;int _day;//成员函数//......2.声明和定义分离:成员函数名前需要加类名::.h。
2023-10-26 16:45:08
43
原创 C++入门(2)
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。注意:1. 引用在定义时必须初始化 2. 一个变量可以有多个引用 3. 引用一旦引用一个实体,再不能引用其他实体 以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低1、传参数传引用的效率比较高
2023-10-20 15:27:08
63
1
原创 C++入门(1)
在了解命名空间之前我们来看一组C语言代码现在代码能正常运行,为何在引入头文件stdlib.h之后代码就报错了呢?编译器提示rand重定义,以前的定义是"函数"说明全局变量rand和库里的函数冲突了,stdlib中包含了一个rand函数这时候就出现了一个问题:命名冲突命名冲突分为两种:一种是我们写的互相冲突,一种是我们写的和库冲突C语言的一大问题之一就是无法解决命名冲突的问题我们之前提到C++的一大特点就是对C不足的弥补C++为解决这一问题就产生了namespace(命名空间)这一关键字。
2023-10-20 13:19:37
76
1
原创 算法与数据结构------排序篇(2)
通俗来讲就是找一个元素(key),然后将key元素左边和右边的元素分开key左边的元素要小于key,key右边的元素要大于key左边的一组可以继续找key继续分,右边同样,也就是递归式地分割下去。
2023-10-12 23:09:46
60
原创 算法与数据结构 ------排序篇(1)
排序就是将一串数字按照大小递增或递减地排列起来的操作在了解各种排序算法之前我们需要知道另外一些概念排序的稳定性:如果说一串数字例如:1 3 4 2 7 6 10 4如果说进行多次排序,然后第一个四的位置一直在第二个四之前或者之后那么说明该排序是稳定的数据元素全部放在内存中的排序。数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。
2023-10-12 09:40:04
55
原创 数据结构初阶------二叉树(2)
之前我们提到树的定义递归式的所以实现二叉树之前我们先了解一下链式二叉树的遍历方式前序遍历:将二叉树递归式地按照:根、左子树、右子树执行中序遍历:将二叉树递归式地按照:左子树、根、右子树执行后序遍历:将二叉树递归式地按照:左子树、右子树、根执行以下图为例:前序遍历:1,2,3,NULL,NULL,NULL,4,5,NULL,NULL,6,NULL,NULL中序遍历:NULL,3,NULL,2,NULL,1,NULL.5,NULL,4,NULL,6,NULL。
2023-10-02 22:16:25
193
1
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人