自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

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

原创 利用锁和条件变量实现线程安全的阻塞队列

阻塞队列中的条件变量的作用是:让生产者 / 消费者线程在 “条件不满足时(队列满 / 空)”具体实现涉及到多线程的一些知识以及pthread库的使用,其实主要就是。(不占 CPU),在 “条件满足时(队列非满 / 非空)”,而非无意义地轮询检查。

2026-02-17 11:39:02 45

原创 mcp的简单理解和最小demo

Tools (工具) : 模型可以调用的可执行函数(如“计算器”、“查询天气”、“执行代码”)。Agent 通过工具对外部世界产生影响。Resources (资源) : 模型可以读取的数据源(如文件、API 返回的 JSON、数据库记录)。类似于给模型提供“参考书”。Prompts (提示词) : 预定义的提示模板,用于指导模型如何与特定工具或资源交互。解决的问题 :在没有 MCP 之前,每个 Agent 框架都需要自己定义一套连接工具的接口。

2026-01-05 15:34:27 516

原创 xv6 第一章 操作系统接口

操作系统的任务是在多个进程之间共享一台计算机资源,并提供比底层硬件更有用和更有效的服务。操作系统抽象硬件,比如让用户程序不用关心使用的是什么类型的磁盘硬件,也为程序之间提供了可控的交互方式,使得不同的程序可以共享数据、协同工作。操作系统的接口设计原则应该,这些接口组合起来能发挥强大的作用。xv6 仿照 Unix 系统的风格,模仿了 Unix 的内部实现,理解 xv6 是理解其他操作系统的良好开端。xv6 采用传统的内核形式,如下图所示:一个进程包括当一个进程需要内核服务的时候,它会调用一个。

2025-10-24 16:49:23 850

原创 xv6 第二章_操作系统架构

Xv6(和其他 Unix 操作系统一样)中的隔离单位是一个进程。用户/管理模式标志地址空间线程的时间切片其中trampoline和trapframe位于每个进程用户内存空间的顶层,各占一页。虽然这两页映射在每个进程的虚拟地址空间中,但其内容由内核管理。Trampoline 页(跳板页)包含用户态和内核态切换时执行的汇编代码。每个进程的虚拟地址空间都映射相同的 trampoline 物理页,因此该页是所有进程共享的。Trapframe 页(陷入帧)

2025-10-24 16:37:56 963

原创 xv6 文件系统总结

文件描述符(File Descriptor) → 路径名(Pathname) → 目录(Directory) → 索引结点(Inode) → 日志(Logging) → 缓冲区高速缓存(Buffer Cache) → 磁盘(Disk)根据磁盘 block 的大小,boot 和 super 可能在同一块,也可能在相邻块(这里是相邻块,根据后面的数据可以推算:10000 - 9953 - 2 - 13 - 30 = 2)。多个 block 操作形成事务,记录文件系统读写操作,在突然断电的时候,保证数据一致性。

2025-10-20 20:58:03 1079

原创 操作系统启动过程

操作系统的启动过程简而言之就是:上电后,BIOS 会进行 CPU 初始化、硬件自检,并找到引导设备的第一个扇区(MBR),执行其中的引导代码。引导代码进一步定位并加载完整的引导程序,之后根据 MBR 的分区表找到活动分区,从而确定操作系统所在的磁盘位置。随后把操作系统的内核加载到内存中,操作系统开始运行,内核再执行初始化进程,完成系统初始化。

2025-10-20 14:25:10 622

原创 mit6s081 lab9 file system

short type;uint size;uint dev;uint inum;int ref;int valid;short type;uint size;实验核心修改点主要函数inode 增加双重间接块索引bmap()itrunc()实现符号链接系统调用及解析sys_open()实验一:通过增加双间接块扩展文件系统可支持文件大小;结果如下图所示:[外链图片转存中…(img-DqbgBAMh-1760455284134)]实验核心修改点主要函数inode 增加双重间接块索引。

2025-10-14 23:22:40 842

原创 mit6s081 lab8 locks

struct {struct {// 哈希表:从 dev+blockno 到 buf 的映射} bcache;void// 初始化哈希桶i++) {// 初始化缓存块i < NBUF;i++){对象是否在内存中是否可每 CPU 独立是否需要全局同步优化方式空闲内存(kalloc)✅ 是✅ 可以否每 CPU 独立空闲链表磁盘缓存(bcache)✅ 是❌ 不行✅ 必须哈希分桶 + 每桶独立锁虽然磁盘缓存也使用内存,但它存储的是。

2025-10-14 15:36:34 782

原创 mit6s081 lab7 Multithreading

实验的主要内容就是了解线程是如何切换的,通过保存和恢复上下文信息,使得线程可以透明地切换。同时对于多线程并行的情况,对于共享数据的更改,需要上锁保证共享变量不会因为线程并行出错。

2025-09-28 17:01:53 678

原创 mit6s081 lab6: copy of write fork

写时复制fork的实现包含一些要点:当fork创建子进程的时候,为子进程分配页表,但是此时父进程和子进程的页表项都设置不可写,并分配一个权限位表示是否位cow页面,然后子进程的页表项都映射到父进程的物理页面中,当子进程中需要对物理页面进行修改的时候,这个时候,会触发中断,中断处理程序,会为子进程分配真正的物理页面,同时修改子进程的页表项为可写,并将其映射到刚分配的物理页面中,中断返回的时候,子进程可用修改读写页表项指向的物理内存的内容。修改kalloc()函数,将对应物理页面的引用计数设置为1;

2025-09-23 21:34:27 1067

原创 xv6 Lab5: lazy page allocation page fault

这个实验主要还是考验是否明白了lazy allocation的过程,理解lazy allocation是在遇到页面错误的时候才去真正分配物理页面,其处理在usertrap函数中,usertrap函数中交代着当用户陷入的时候,操作系统的行为。

2025-09-12 17:07:11 1155

原创 可执行文件运行,操作系统中发生了什么

比如执行exec()系统调用,此时陷入内核中断,切换到内核态,会为可执行文件创建一个新进程,先为该进程分配一个用户页表,然后把可执行文件的ELF头读取到内存缓冲区中,然后根据里面的信息为进程分配足够的空闲物理内存空间。然后根据ELF头里面代码段和数据段要放置的虚拟地址,这个时候,虚拟地址和物理地址都有了,然后根据这两个地址建立其映射关系就好,也就是填充页表中的页表项(如何建立映射关系,见第3节)。然后把硬盘中可执行文件的代码段和数据段根据虚拟地址拷贝到对应的物理地址中。

2025-08-24 11:36:45 364

原创 如何用github记录mit6s081-2020-labs学习过程

这个课程中包含了许多分支,每次lab都在不同的分支,我们首先在github网站上面新建一个仓库,不要勾选add readme,不然会创建一个默认的master分支。可以看到现在有两个分支,可以理解为第一个util分支为本地的,第二个util为远程仓库的util分支,我们在本地的util分支上写好代码以后,通过。这三条命令就能把本地的util分支的内容传到远程仓库的util分支上了。每次实验时,先切换到对应的本地分支,比如util分支,就使用。可用查看一下git的配置情况,使用。的分支表示目前所在的分支。

2025-08-18 14:48:25 492

原创 mit. 6s081 lab2

本文摘要了MIT 6.S081实验2的前瞻学习内容,重点介绍了xv6操作系统的系统调用机制。通过分析initcode.S汇编代码,展示了用户程序如何通过寄存器传递参数并执行ecall指令陷入内核态。文章详细解析了用户空间(user.h,usys.pl)和内核空间(syscall.h,syscall.c)的系统调用处理流程,包括参数传递、调用号识别和返回值处理。同时介绍了proc.h中定义的进程上下文数据结构,包括context、cpu和trapframe等关键结构,这些结构在内核调度和进程切换中起着重要作用

2025-08-18 14:46:57 489

原创 6s081实验1

第一个实验写得磕磕碰碰,参考了很多大佬的思路和代码,不过也算有收获。

2025-08-11 16:40:21 911

原创 6s081环境配置以及使用vscode连接本地wsl2

课程:6s081的2020版本的:https://pdos.csail.mit.edu/6.S081/2020/schedule.html。

2025-08-04 10:55:12 622

原创 KuiperInfer第八课-实现resnet推理

加载预训练的模型读取输入图像并进行预处理使用模型对图像进行前向传播,得到预测结果对预测结果进行后处理,得到图像的类别输出分类结果。

2025-07-18 16:04:32 1055

原创 while(len--) {}

while(len--){}会先用len进行判断,然后对len进行减一,然后执行循环体,注意无论是否执行循环体,len都会被减一,以后不要用这种操作了。

2025-07-15 19:38:40 432

原创 kuiperinfer跟学第七课——表达式层的实现

摘要:本文介绍了kuiperinfer第七课关于表达式层的实现,重点讨论了PNNX中表达式层的定义和工作机制。表达式层通过表达式折叠和抽象语法树(AST)技术消除中间变量,将复杂计算视为整体操作。文章详细讲解了词法解析过程,包括Token类型定义、Token结构体设计以及语法树节点构建。Tokenizer方法通过预处理去除空格后逐个解析字符生成Token序列,为后续语法分析奠定基础。该方法采用高效的空格去除策略和使用CHECK宏进行输入验证,体现了良好的工程实践。

2025-07-09 15:21:19 963

原创 Kuiperinfer跟学——第六课池化算子和卷积算子的实现

池化可以看作对特征图的一种精炼提取,用一个值来代表池化窗口的特征,常见的池化操作有平均池化和最大池化,池化的作用是减小特征图尺寸,缓解深度学习模型对位置的敏感性。以平均池化为例,根据上图可以看出,池化窗口大小为2x2,然后池化窗口会在特征图上面进行滑动,方向是先从左到右,然后从上到下,确保雨露均沾,同时也要设定每次移动的步长stride,同时也可以在计算前对特征图周围进行填充,padding。

2025-07-05 15:58:39 809

原创 关于const和C++中变量存储方式

被称为自动变量 (automatic variable),这意味着它们在所属的函数被调用时自动产生,在该函数结束时消亡。自动存储使用的数据结构为栈,意味着进入函数内部后,变量按照顺序依次加入栈中,离开函数体时,按照先进后出的顺序被销毁。在常量对象上调用常量成员函数是合法的,但在非常量对象上调用常量成员函数是不合法的。非静态const成员变量是每个对象独立拥有的,静态const成员变量是类拥有的,每个对象共用的;注:这里的分配内存是指能够找到其内存地址,比如通过&取得地址,而不是不占用内存的意思;

2025-07-03 16:44:50 824

原创 对C++中static的一些理解

✅改变链接性(external → internal),限制访问范围在当前编译单元(即当前.cpp文件);✅改变生命周期(block → 程序运行期间),初始化一次,之后值会一直保留;✅属于整个类而非某个对象;✅不依赖于对象,只能访问静态成员;✅限制链接性为内部,只在当前文件可见。

2025-07-03 16:43:03 457

原创 Kuiperinfer跟学第五课——算子和注册工厂

public:/*** Layer的执行函数* @param inputs 层的输入* @param outputs 层的输出* @return 执行的状态*//*** Layer的执行函数* @param current_operator 当前的operator* @return 执行的状态*//*** 返回层的权重* @return 返回的权重*//*** 返回层的偏移量* @return 返回的偏移量*//*** 设置Layer的权重。

2025-06-30 10:05:08 763

原创 KMP算法详解

指针j:指向与该后缀相同的前缀的末尾,即next[i]。如果指向元素不相等,则指针j需要回溯,**具体应该回溯的位置结合下图进行理解。这个时候就要对j进行回退,因为j下标之前的m长度的字符串和i前面m长度的字符串相等,假设next[j-1]=n,那么下标为j-1的字符串中前n个字符串和后n个字符串相等,下标为i-1的后m长度的字符串中,前n个字符串和后n个字符串也是相等的,所以换算一下,下标为j-1的字符串中,前n个字符串等于下标为i-1的后m长度的字符串中后n个字符串,所以令j=next[j-1];

2025-06-26 15:52:16 808

原创 第四节课-构建计算图关系和执行

思想:基于广度优先的拓扑排序,首先遍历图的每一个节点,统计每个节点的入度,然后将入度为0的节点存入队列中,然后依次取出队列中每个节点,每取出一个节点,就把该节点放入到结果中,然后更新图中每个节点的入度,并把入度为0的节点加入到队列中,重复这个步骤,直到队列为0,如果结果节点的数目和计算图的节点数目不一致,则说明存在环,存在环的话,环中的节点始终入度不能为0,无法加入到结果中,这就导致结果节点的数目少于计算图中的节点。在Init阶段,只是记录了每个节点儿子节点的名字(存放在每个节点的。

2025-06-25 16:42:14 908

原创 KuiperInfer跟学——第三讲 计算图的定义

pnnx是一种类似于onnx的模型中间表示结构。KuiperInfer计算图的设计参照了pnnx。pnnx介绍:https://zhuanlan.zhihu.com/p/427620428一个计算图中包含了操作符、操作数。下面是计算图这个类的定义public:Graph();~Graph();#endifprivate:首先说一下load函数if (!

2025-06-20 15:37:29 464

原创 哈希法——代码随想录

两数相加和四数相加II这两道题解法类似,不涉及对下标和值的去重,用哈希法较为容易;三数之和、四数之和是在同一个数组里面找答案,同时涉及对于下标和值的去重,使用哈希法去重麻烦容易出错,所以采用双指针法,先对数组进行排序,然后利用for循环限定双指针的查找范围,并利用和相邻元素的判断来达到去重的目的;

2025-06-11 16:34:02 737

原创 C++中的右值引用与移动语义的理解

右值引用:C++中定义的对右值的引用// 这里a的地址就是这个语句中5的地址int b = 5;// 这里b的地址和这个语句中5这个临时变量**移动语义:**对于含有指针类型作为成员数据的类,使用移动而不是深拷贝进行初始化或者赋值。具体体现就是类的移动构造函数和移动赋值函数;也就是传入一个右值引用(就相当于给这个临时变量),然后让本对象的指针的值直接等于该临时对象指针的值,然后将临时对象的指针再置为空。这样避免了深拷贝那样的内存开销。

2025-06-06 18:23:30 403

原创 KuiperInfer跟学第二课——张量的构建与实现

思路:根据面对对象的思想,Tensor的成员数据应该包括数据和形状,这里用cube类型存储数据,用vector类存储形状;首先对于构造函数,有用形状构建的,有用值构建的,也有同时形状和值构建的情况,Tensor应该涵盖全面的基础操作,比如形状变换、值的转换、定位操作、切片操作、赋值、边缘填充等//// tensor头文件template<>// 待实现template<>public:/*** 创建张量* @param channels 张量的通道数。

2025-06-06 18:18:55 1085

原创 KuiperInfer跟学第一课——环境配置

*本机环境:**Windows11+wsl2(Ubuntu24.02)+Clion(2024.3.6 Windows);

2025-06-05 09:21:53 879

原创 并发和并行的通俗理解

2025-05-20 10:25:56 184

原创 nvidia-container-toolkit安装与配置

nvidia-container-toolkit是Docker与NVIDIA GPU之间的桥梁,也就是只有安装了nvidia-container-toolkit,Docker才能使用本机的GPU;

2025-05-19 11:00:30 995

原创 C++中,前++和后++的区别

大概前++和后++的过程就是这样,所以(a++)这里返回一个临时对象的值,该值等于原来a的值,但其实a本身的值已经加了1,所以后面再乘以a的时候,a的值已经等于5;由于int类型的前++和后++的具体实现要去查看汇编代码,比较麻烦,所以这里定义一个新的类型来描述前++和后++的行为;本来想着b应该等于16,但结果等于20;

2025-05-15 11:26:20 214

原创 C++中六个特殊成员函数的关系

4、如果显式声明了析构函数,但是编译器仍然会自动提供默认的复制构造函数和复制赋值运算符,所以需要用到移动构造函数或移动赋值运算符的地方会自动使用复制构造函数和复制赋值运算符;默认构造函数、复制构造函数、复制赋值运算符、析构函数、移动构造函数、移动赋值运算符。2、如果显式声明了默认构造函数,编译器仍将自动提供其他五种特殊成员函数的默认定义;1、如果显式声明了任何构造函数,那么编译器不再自动提供默认构造函数;复制赋值运算符,那么编译器则不会自动提供移动构造函数。3、如果显式声明了析构函数、复制构造函数。

2025-05-09 16:06:50 315

原创 关于string类的构造函数

一、string(const char* s, size_type n, const Allocator & a=Allocator());这个构造函数接受一个C风格字符串,并指定复制这个C风格字符串的n个字符作为该string对象的内部数据成员;这里就是需要注意一下,当n大于s的长度的时候,string对象会继续获取s后面的内存区域的值,所以这里调用该string的size()方法的时候会返回n;二、string(const string & st, size_type pos, size_type

2025-05-05 17:46:22 274

原创 C++中一些关于何时何处定义类或函数的问题

因为只有在编译器编译过程中遇到模板的实例化(也就是指定了模板使用的具体类型)的时候,编译器才会按照模板定义来生成对应的实现代码,当模板在头文件中定义的时候,在预处理阶段,编译器会把代码文件中包含的头文件内容引入进来,这样在遇到模板实例化的时候,编译器就知道如何根据通用模板类的定义来生成对应的实现,而加入模板的定义放在其他代码文件中,那么本代码文件在遇到模板实例化的语句的时候就找不到模板的定义,就无法生成对应具体类的实现代码;2、内联函数➔必须头文件或者当前代码文件中定义,不能在其他的代码文件中定义。

2025-04-29 16:39:54 531

原创 问题:windows上用vscode远程连接wsl2 ubuntu运行opencv代码时, 如何调用windows机器的摄像头;

问题一:由于wsl2无法直接调用本机的摄像头,所以首先想要调用windows机器上的摄像头,要使用rtsp服务,在windows系统上建立一个rtsp服务器(使用easydarwin来建立),通过ffmpeg将本机(windows)的视频流推送到rtsp服务器上,然后在wsl ubuntu系统中使用ffmpeg去拉取rtsp服务器上面的视频流进行处理;简单来说,就是建立一个rtsp服务器,将wsl无法直接读取的视频流放在这个服务器上,然后通过这个rtsp服务器作为中转站,让wsl可以去拉去到视频流;

2025-04-23 18:02:39 527

原创 浅谈类的复制构造函数和赋值运算符

对于第二行和第三行代码,有用到=,但是不一定会调用赋值运算符(如果编译器的实现方式是:首先使用复制构造函数创建一个临时变量,然后将该临时变量的值赋给新对象,这种情况就会调用赋值运算符),这去取决于编译器,我用的g++编译器并不会调用赋值运算符;对于第一种按引用传递的函数,并不会调用复制构造函数,因为并不涉及创建临时对象,也就是整个过程并没有创建新的对象,所以并不会调用复制构造函数;默认的复制构造函数逐个复制非静态成员,复制的是成员的值,也就是浅复制,对于含有指针类型的成员数据,这种浅复制是不行的;

2025-04-08 16:12:00 311

原创 C++中的浅拷贝和深拷贝

浅拷贝只是将变量的值赋予给另外一个变量,在遇到指针类型时,浅拷贝只会把当前指针的值,也就是该指针指向的地址赋予给另外一个指针,深拷贝在遇到指针类型时,会先将当前指针指向地址包含的值复制一份,然后new一个新的内存空间,然后把复制的值放到该内存空间中,,只是两个不同地址包含的值是相同的;

2025-04-06 11:36:23 306

原创 C++中,应尽可能将引用形参声明为const

我们的目的是交换传入参数的值,如果不使用引入形参,如swap(int a,int b),那么该函数将按值传递,并不会实际改变传入参数的值,所以这种情况需要使用引用形参;2、节约内存和加快速度,对于基本类型可以不用使用引用参数,但是对于结构、数组或者较为复杂的类对象,使用引用参数可以避免传参时创建值相同的临时变量,而是直接使用引用的变量;,然后做Add类的加法运算,但是由于前面提到的引用形参没有使用const ,所以这里的临时变量没法传给函数;1、需要改变传入参数的值的时候,不能声明为const;

2025-04-04 10:59:29 386

1发达发达发发发发发 发发达发达发

1发达发达发发发发发 发发达发达发

2026-03-05

空空如也

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

TA关注的人

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