自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(39)
  • 收藏
  • 关注

原创 【线程同步】

就好比预约了图书馆位置,申请成功了你就可以在一段时间内由自己独占,如果有其他多人申请,就让申请者排队等待,一旦使用完毕了,把位置腾空了,可以再次申请获取该位置的使用,但需要排队,在之前申请的人后面排队进行等待,直到再轮到你。这样,每一个申请的人都可以的得到该位置的使用机会。只使用互斥锁是可以保证线程安全的,但是如果一个线程访问临界资源的时候获取互斥锁,访问完临界资源后释放锁,可能下一步的调度还会是该线程,继续抢占互斥锁这个资源,不断获取不断释放,导致其他的线程不能得到调用,这就是进程饥饿问题。

2024-05-30 19:23:42 313

原创 【线程的互斥】

线程互斥和安全

2024-05-26 15:35:04 807

原创 【Linux线程】

如果不让主进程一直的执行下去,主进程结束退出,如果线程要处理的任务的时间是100个单位,而主进程创建线程完成后进程就立即结束,则线程也跟着退出。对于父子进程来说,各自有一份独立的虚拟地址空间,当在内存的共享文件有其中的一个进程对数据进行修改的时候,操作系统就会对在内存的文件进行写实拷贝。但是对于进程来说,他们是独立的,所有进程间的交互就变得复杂,共享信息的时候需要进程间通信的机制。在linux当中,线程被称为轻量级进程,轻量级进程是基于进程实现,直接复用了进程的原理,但也可以实现和多线程的一样的功能。

2024-05-05 21:03:42 792 2

原创 【Linux信号】

信号发送的本质是操作系统对发送信号的硬件信号进行处理,然后操作系统向进程的一个信号位图表的一个位置由0变1,实际是硬件的信号通过操作系统写到进程的进程控制块的信号位图进行写入。当进程在处理信号对应的处理方式的时候,叫做信号的抵达,进程对信号的操作方式可能有忽略signal(int sign,SIG_IGN),默认的处理方式signal(int sign,SIG_DFL),和自定义捕捉的处理方式。当信号产生到来的时候,进程不一定知道该信号的到了,所以信号对于进程正在工作是异步的,并不同步。

2024-03-03 15:33:05 943

原创 【进程间通信】

如果创建成功,返回创建共享内存的标识id,如果创建失败,返回-1,key值即ftok函数生成的地址变量,size即要使用多少字节的共享内存,shmflg是创建共享内存的模式,IPC_CREAT | IPC_EXCL | 0666,即没有就创建,然后以权限0666的方式使用共享内存,另一个进程的shmflg填0即可。进程有独立性,但是进程间也可以有信息的交流,叫进程间通信,进程间通信可以通过匿名管道,命名管道,共享内存来进行通信。因为是匿名,找不到进程的路径,所以要在父子关系的进程使用匿名管道。

2024-02-28 09:24:34 1311

原创 【进程替换】

函数进行进程替换,path为文件路径,要找到替换的进程,arg为指令的字符串,替换的进程如何执行,最后要加上NULL表述结尾。进程替换后,代码和数据会改变,所以上述代码和结果为什么next:process没有打印出来,这是因为代码和数据不在是原来的了。子进程的作用是为了和父进程执行不一样单位任务,创建的子进程是和父进程共享代码和数据的。所以要使子进程做不同的任务,就要有新的代码和数据,在Linux的task_struct要找到新的代码和数据。进程替换其实并没有创建子进程,只是不再是原来的代码和数据。

2024-02-25 16:10:36 149

原创 【进程地址空间】

这是因为父进程创建子进程的时候,拷贝了父进程的一个表,叫进程地址空间。因为是拷贝的,所以他们虚拟地址一样,上层用户看到同样的地址,实际上,进程还要通过一个叫页表的表来映射虚拟地址和物理内存的关系,一旦父子进程对数据有修改的操作,操作系统会为第一个改变数据的进程在物理地址重新找到一个可以使用的物理内存,改变页表的映射关系。进程运行的时候,地址空间通过页表映射到物理内存,发现没准备好资源,页表会发送缺页中断,然后操作系统会为该进程重新申请物理内存的资源,让进程的地址空间映射到物理地址。引用深入理解计算机系统。

2024-02-24 15:35:10 1591

原创 【进程状态】

一个进程在就绪的状态,是可以随时被CPU调度到的进程,因为一个CPU只能处理一个进程,而且计算机要有并发执行的能力,要运行的进程很多,所以就绪状态的进程会链接到一个双向的运行队列当中,当一个进程在CPU被执行完,进程退出,就可以调度运行队列里的优先级高的进程。在等待键盘资源的期间,进程不是运行的状态,而是等待的状态。非阻塞等待需要在一个轮循的方式等待,即父进程的不能退出,或者父进程要在子进程后面退出,否则,如果父进程先退出,子进程会变成孤儿进程,不在是原来的父进程管理了,由进程pid位1的进程来管理。

2024-02-23 15:48:23 878

原创 【进程创建】

父进程创建子进程后。数据发送了改变,哪个进程先对这个数据改变,操作系统就会申请新的内存给该进程,这是为了保证进程的独立性,互补干扰,让进程有独自的存放空间。查看父进程可以调用getppid(),当程序被运行的时候,我们发现两个循环体尽然都有在执行,而且他们的进程pid都不一样,但是子进程的ppid和父进程的pid一样,说明子进程是由父进程创建的。linux中第一个创建的进程是init,操作系统以后的进程创建,就可以依靠该init进程为父进程创建子进程,创建的子进程也可以做为之后进程创建的父进程。

2024-02-22 15:07:35 1460

原创 【进程概念】

对于一个在磁盘可执行的二进制文件,也可叫做可执行程序。对于一个可执行的程序,程序有自己的代码和数据。一旦运行起来,就会在计算机内部运作起来。根据冯诺依曼体系,一个程序要被运行起来,先是要加载到内存当中,然后再到CPU调度。当代计算机中,能运行一个程序,就能运行多个程序,然后每个二进制的可执行文件程序都像在自己干自己的事情,互不干扰。这就是在计算机运行的程序。

2024-02-21 18:29:47 470

原创 【操作系统】

以Linux操作系统为例,Linux操作系统是一款软件,是通过大量的C语言和一些汇编的语言来进行编写的。通过上面的结论,知道了操作系统是管理计算机硬件和软件的一款软件,操作系统是在计算机硬件和软件之间的。操作系统中有大量的内核数据结构和数据对象,这些数据结构和对象是用户的数据,这些大量的数据结构和对象要由操作系统进行管理。操作系统主要的功能 :①进程管理②存储管理③设备管理④文件管理。

2024-02-21 08:21:35 708

原创 【冯诺依曼体系】

因为虽然比CPU存储的效率低,但是相对于外设的输入设备是有非常大的提升,所以先把外设资源加载到内存当中,然后CPU再从内存获得数据,CPU执行完毕后,再以极短的时间内继续再内存获得要运行的数据,避免CPU被空闲,浪费资源。CPU的效率是最快的,比如磁盘这个外设,磁盘存储的速率相比于CPU是非常非常的慢的,如果磁盘直接和CPU关联起来加载数据到CPU,CPU很快的运行完第一次的数据,那么下一次的磁盘数据内容还没加载到CPU当中,这就会造成CPU资源的浪费,所以就不会让CPU和磁盘等外设直接有数据的交互。

2024-02-20 15:23:34 684

原创 【C++11 lambda函数表达式】

通过捕捉列表捕捉的参数他们的地址是一样的,所以我们可以采取matable或引用的方式对他进行修改,如果没有采取,我们只能对变量进行使用但不能修改。当使用=(或&引用)进行捕捉时,我们不能在对某个变量或对象进行值(或&引用)得捕捉,这会导致重复捕捉,只能=全部(或全部&捕捉)进行值捕捉,然后对某个变量或对象进行引用捕捉(或值捕捉)。我们可以使用函数指针实现防御值大小比较排序,仿函数实现价格排序比较功能,但是我们如果需要用其他的属性比较,我们就需要在实现类似的函数指针或仿函数。&引用捕捉,=值捕捉。

2024-01-05 10:53:53 962

原创 【C++智能指针】

智能指针是行为类似于指针的类对象,可以通过这个对象进行动态内存资源进行管理。如果程序员进行了动态内存的申请,执行程序的开始到结束,如果没有进行正确的释放,就会导致内存泄漏,失去对该内存的管理控制。如果使用了智能指针进行管理,当程序结束时,智能指针这个对象将自己调用析构函数,进行资源的释放。

2024-01-05 10:34:11 798

原创 【C++11 initializer_list 列表初始化】

这里的a1用大括号进行初始化,开辟的空间里有5个数据,一开始的五个数据在initializer_list,在常量区,因为initializer_list有指向开始和结束的两个原生指针(_First和_Last)和迭代器,和成员变量begin()和end(),所以支持范围for的使用方法。//代表了开辟了三个空间,也是initializer_list初始化的,分别存储了1,2,3三个值。//代表开了一个空间,是用initializer_list初始化的,开辟了一个空间,储存的值是10。

2023-12-30 20:57:15 354

原创 【C++11可变模板参数】

可变模板参数

2023-12-15 14:32:27 28

原创 【散列表(哈希表)————数据结构】

这时候我们就可以把整个字符串的每一个字符用对应的ASCII来进行相加,但是我们有面临另一个问题,比如abc和acb和aad,如果他们都相加,最后的值是一样的,然后所映射的值是相同的,最后还是会多次哈希冲突,造成效率的下降。然后通过映射在表上的位置来获取这个关键字所在的结构体中其他的数据。在开放的拉链法当中,当负载因子是1的时候,我们就需要扩容,因为我们写完希望的是平均一个关键字对应一个哈希表的位置,这才可以让我们的查找,插入,删除的操作的平均时间复杂度为一个常数的时间复杂度。关键字我们使用一个结构体实现。

2023-11-24 10:43:58 41

原创 【C++实现红黑树】

红黑树(Red Black Tree) 是一种自平衡搜索二叉查找树。红黑树是一种特化的AVL树(平衡二叉树),都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能,消耗较小的时间复杂度的一种查找方式。虽然实现的情况非常复杂,但是在最坏的情况下运行效率也是非常可观的,最坏的时间复杂度就是树的最高的高度O(logN)。N即为树的结点数。我们需要用枚举出两种颜色或者两种不同的标记。在定义结点的时候,我们要把第一个结点做为根结点,每个结点需要三个指针。

2023-11-16 21:38:58 30

原创 【C++手撕AVL树】

如果左边比右边高一个高度差,这个结点的平衡因子就是-1,如果右边比左边高一个高度差,平衡因子就是1,在以此类推,往上遍历,左高自减,右高自增,如果高度差为2的时候,就不能再往上++或–了,因为平衡因子为2或-2的时候就不是平衡的条件。把发生第一次高度差的节点的左子树给这个节点的_parent指向的父亲节点的右子树,节点的右子树的这个节点给这棵树的根结点的左子树,然后这个节点做这棵树的根,原来这个节点指向的_parent作为这个节点的左子树(根节点),原来的根节点作为这个节点的右子树。不平衡的情况有很多种。

2023-11-10 16:57:59 47

原创 【leedcode——随机链表的复制】

给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点。3.创建拷贝的结点,然后把原链表相对应的结点的值赋值,再把拷贝的结点链接到原结点相对应结点的下一个。

2023-11-01 20:56:48 74 3

原创 【C++搜索二叉树】

生成一颗树,我们树的每个结点都要有指向左子树和指向右子树的两个指针,和一个存放数据的变量。我们可以写一个结构体或类来表示。第一个二叉树符号搜索二叉树的条件,第二个如果把10的结点换成比13大的数或者比8小的数都不会满足搜索二叉树的条件,第三个二叉树如此。如果最开始是一个空树,我们直接把根结点的结构体中赋值,然后把指向左子树和指向右子树的指针指向nullptr。如果调用自己生成的拷贝构造,会是浅拷贝,所以需要自己生成拷贝构造。搜索二叉树是一个排序的树,或者是一课空树,搜索二叉树有三种性质。

2023-10-30 13:38:28 27

原创 【C++多态】

(因为派生类对象给基类对象赋值的时候,调用了拷贝构造,实例化的对象就是基类的对象了,就构成不了多态,但是不会把虚函数表的指针进行拷贝,直接再生成一个虚表指针,如果说可以拷贝,那虚表可能是派生类的,不是基类的,但是基类的对象不能调用派生类的虚函数)。我们可以发现,这种单继承的类的每个对象都会有一个虚函数表,每个表的地址都不一样,如果基类的虚函数没有在派生类进行重写,派生类的虚表里存没有重写的虚函数地址跟基类的一样,如果重写了,就会是新的地址。类型的方式获取__vfptr的空间再解引用即可得到虚函数表的地址。

2023-10-25 11:46:28 69 2

原创 【类继承和多继承】

这里一个派生类学生的对象s,和一个基类person基类的对象man,引用rman,Preson* 的pman,这里s对象给man对象赋值,就把派生类中基类的对象那部分赋值给man对象,如果是rman引用,就把派生类中基类那部分的对象起别名,如果是指针pman,就指向派生类中基类的那一部分的地址。在继承中,如果基类和派生类都有同名的函数,同名的函数构成了一种隐藏的关系,只要是函数名相同了,不管类型还是参数的不同,都构成了隐藏,他们不构成重载,因为虽然同样的函数名,但他们却是不同的作用域。

2023-10-18 15:28:32 76 4

原创 【C++模拟实现优先级队列priority_queue】

优先级队列是对一个一个vector进行大小堆的一个建立,默认的是建立一个大堆,因为less<>()是他的默认函数,less<>()是一个函数对象。less<>()是生成大堆,vector的首元素将会是最大值,如果是想建立一个小堆,我们可以传一个greater<>()函数对象。这两个函数可以通过仿函数来实现,是一个可以行使函数功能的一个类,函数对象可以以函数方式与()结合使用的任意对象,即定义了函数operator()()。仿函数多用在STL中。比如less<>,用一个类模板,定义一个less的类。

2023-10-08 17:07:21 48 1

原创 【动态规划————买股票的最佳时机含冷冻期LeedCode.309】

给定一个整数数组prices,其中第 prices[i] 表示第 i 天的股票价格。​设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

2023-10-06 16:02:29 39 2

原创 【C++模拟实现队列】

队列是一种数据先进先出的一种数据结构,是一种容器适配器,queue可以使用底层模板deque来实现。但queue不允许随机访问队列的元素,没有迭代器,不能遍历queue,queue可以实现尾部插,和队首删除,可以访问到队首和队伍的数据。检查队列大小和判断队列是否为空的功能。

2023-10-05 22:27:05 63

原创 【C++模拟实现stack栈】

栈是一种先进后出的一种数据结构,当访问栈的数据结构的时候,我们可以访问栈顶元素,再C++中,栈是一个容器适配器,栈可以使用vector和list还有deque双端队列进行适配。

2023-10-05 11:16:45 65 1

原创 【leedcode翻转链表】

当head->next指向new的时候,就会没有原本链表的下一个位置,所以tmp之前记录的head->next就可以重新给head赋值。然后继续原来的步骤,先把head->next赋值给tmp,然后把head->next重新指向new,head的值赋值给new,tmp再赋值给head。然后再把head->next指向一个new的结点(new结点为NULL),这样原来的链表的头结点就会指向NULL。把链表1->2->3->4->5->NULL翻转成5->4->3->2->1->NULL。

2023-09-11 22:47:21 26

原创 【vector模拟实现】

vector是C++ STL的一种容器,是一种顺序表,可以按照连续的空间储存数据。使用vector可以方便我们使用,因为再使用的时候不再需要考虑空间扩容的问题,而且提供函数接口来进行增删查改的操作,不再需要我们自己来进行具体的实现,直接使用上层的接口来直接通过底层代码进行程序。且支持迭代器。vector只需要三个成员变量就可以实现它所需要的条件,一个是连续空间的起始地址,一个是连续数据结尾的地址,另一个是整个空间大小最后的地址,因为vector可以存放不同的数据类型,所以我们可以使用模板。这里的三个指针是

2023-09-05 22:52:21 81 1

原创 【string模拟实现】

string模拟

2023-08-27 19:40:11 142 5

原创 【C++类的构造,析构,拷贝构造,赋值运算符重载的成员函数】

**拷贝构造对于某些类是非常重要的,这里的栈就是其中之一,因为如果自己不写拷贝构造,就会调用默认生成的拷贝构造,而默认生成的拷贝构造是一种浅拷贝(值拷贝),对于栈而言,它需要开辟空间,一旦浅拷贝,将会有两个指针指向同一块空间,当程序结束时,调用析构函数时,就会造成同一块空间被释放两次,就会造成程序的崩溃。实例化一个st时,会走初始化列表,如果没有编写初始化列表,私有的成员如果是内置类型,将会生成随机值,如果是自定义类型,将会调用自己的构造函数。当程序结束时,先调用s3的析构函数,把s3._a的空间释放。

2023-08-15 09:04:36 45

原创 【C++的类】

1.C语言是一门面向过程的一门编程语言,而CPP是一门面向对象的语言。如果要知道一架无人机从起飞到降落的过程,在面向过程中,首先地上操作人员要启动开关,无人机自行操作,在跑道到达一定的速度时,然后向上拉升,达到一定的高度时候在平稳飞行,块到达目的地的时候在降低飞行高度,在降落过程中,接触到跑道,就进行反向制动,最后无人机速度降为零,关闭开关。在面向对象中,只需要关注操作人员和无人机,在天空的一系列行为只需要无人机自行处理,我们就不需要过多关注。

2023-08-11 18:10:44 38 1

原创 【C++的引用】

C++使用了一种符合类型,叫引用变量。(符号&)跟C 和 C++的取地址符一样,作用有点类似,但不是取地址符号。引用是给一个变量或者对象取一个别名,但是编译器并不会给引用开辟空间。可以说引用和它引用的对象是同一块空间,在编译器的角度来说。可以发现val变量和它的引用变量reference的地址是一致的,reference被声名为int& 的类型,意思是指向int 变量的int& 的引用。引用的作用有点类似指针,但引用并不是指针,虽然它看起来有点像。

2023-07-29 23:48:43 30

原创 【C++的开始第一步】

命名空间是C++的一个特性,使用命名空间可以在编写大型程序或者多人多厂商编写程序组合的时候可以没有命名的冲突,造成重定义。其在C的基础上,增加了类的概念,并引入了引用,重载,多态的理念,使面向过程的C语言进步到面向对象的C++语言。这里的cin 是一个C++标准的输入流对象,使用右移运算符 “>>” 从设备键盘取得数据,送到输入流对象cin中,然后送到内存,cin也是。可以发现,如果是用自己的命名空间的变量,输出的是自己的初始化。这里的用法是将std命名空间全部展开,可以使用命名空间里面的所有名称。

2023-07-19 23:50:37 46

原创 自定义类型中的结构体类型

结构的声名是描述了一个结构的组织布局例如:在结构体中,可以声名多种数据来描述这个结构体变量的多种成员变量。比如描述一本书的书名,价格,出版社,作者,日期等等。int date;} b;//声名一个结构体的时候创建了一个全局的结构体变量b int main() {0 };//定义一个结构体变量B并初始化为0 struct book * pb;//定义了一个结构体指针变量pb B = {"C语言" , 100 , 2023 };//给结构体变量B的成员变量赋值 return 0;

2023-03-19 21:59:59 72

原创 字符串函数

dest,const char* str):**:该函数接收的是两个数组的首地址或两个指针,源字符串用const修饰,解引用的内容不能修改,函数返回的是一个char*的指针,是目标空间的首地址。*:该函数接收的是两个数组的首地址或两个指针,源字符串用const修饰,解引用的内容不能修改,函数返回的的是一个char*的指针,是目标空间的首地址。函数接收的是两个指针,返回的是一个有符号的整数,如果第一个跟第二个不匹配,第一个大于第二给,返回值大于0,否则小于0,如果两个相等,则返回0。

2023-03-15 18:35:16 42

原创 指针运算图解

【代码】指针运算图解。

2023-03-12 09:24:34 43

原创 浮点数在计算机的储存方式

浮点数内存中的存储和读取方式

2023-02-23 14:33:56 101

原创 scanf的一些误区和错误

对于初学者使用scanf出现的问题和错误

2022-12-24 12:02:04 254

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除