操作系统考研笔记(王道408)

news2024/11/17 16:27:47

文章目录

  • 前言
  • 计算机系统概述
    • OS的基本概念
    • OS的发展历程
    • OS的运行机制
    • OS体系结构
    • OS引导
    • 虚拟机
  • 进程和线程
    • 进程和线程基础
      • 进程
      • 进程状态
      • 进程控制
      • 进程通信
      • 线程
      • 线程实现
    • CPU调度
      • 调度的层次
      • 进程调度细节
      • 调度算法
        • 评价指标
        • 批处理调度算法
        • 交互式调度方法
    • 同步与互斥
      • 基本概念
      • 互斥
        • 互斥软件实现
        • 互斥硬件实现
        • 互斥锁(自旋锁)
      • 信号量
        • 信号量机制
        • 信号量实现互斥同步
      • 经典信号量问题
        • 生产者消费者——基本的分析思路
        • 多生产者多消费者——多种生产者
        • 吸烟者问题——多功能生产者
        • 哲学家进餐问题——连续申请多个资源
        • 读者写者问题
    • 死锁

前言

学校OS课程的知识和408有一定的重叠,但是还不太够,因此我又一次打开了王道的OS课程。

这个笔记同理,只记最关键的内容和思考,直接针对408,基础性的概念性的知识以视频为主。

计算机系统概述

OS的基本概念

在这里插入图片描述
OS提供的服务:

  1. 用户级别:
    • GUI,就是windows
    • 命令接口
      • 联机:有交互性,即cmd命令行
      • 脱机:批处理,即.bat文件
  2. 程序员级别:
    • 系统调用:OS的api
    • 系统调用可以通过c语言的操作系统库函数调用,但是c语言本质上比系统调用还高一级

在这里插入图片描述
异步的前提是并发,程序之间交叉前进,即走走停停,无法预知。

OS的发展历程

在这里插入图片描述

  1. 手工阶段,缺点:
    • 独占
    • 人太慢,机器速度逐渐加快,人拖累机器
  2. 单通道批处理
    • 优:提升预处理速度,不拖累机器
    • 缺:独占
  3. 多通道批处理
    • 优:解决独占,实现并发,提升效率
    • 缺:无交互能力
  4. 分时系统
    • 优:解决交互能力,用户“看起来”独占
    • 缺:没有优先级
  5. 实时系统
    • 优:解决了优先级响应问题,及时可靠

OS的运行机制

在这里插入图片描述
OS内核相当于OS的管理员,因此特权指令只能是内核执行。

平时用户的特权调用,操作都是向管理员申请,而不是亲力亲为。

两个状态的切换:

  1. 升级:特权指令触发中断(硬件),OS响应中断的时候进入核心态
  2. 降级:OS主动修改PSW让出控制权(软件)
    • 修改PSW的指令,本身就是特权指令

在这里插入图片描述

中断和计组第5章衔接

涉及到进程之间的协调,就一定要OS接入,进而需要系统调用。

在这里插入图片描述

需要注意,陷入指令是用户态指令(请求),接下来才会因为内中断进入核心态(执行)

在这里插入图片描述

OS体系结构

在这里插入图片描述

我们OS学的功能,可以放在内核,也可以放在用户,这就形成了大内核和微内核的区别。

微内核暴露的接口多,易于维护和扩展,但是沟通成本大,要反复调用。

在这里插入图片描述

在这里插入图片描述

  1. 分层结构
    • 类似于计网的层次结构,结构清晰,通病是效率偏低
  2. 模块化
    • 主模块分离,模块之间分离,平等
      • 优点:可以同时开发,且效率不错
      • 缺点:模块间的图关系很难把握
    • 动态可加载模块。
      • 可加载说白了就是插件,有没有都不影响运行,因此可以动态加载,比如驱动
  3. 宏内核和微内核
    • 微内核相当于一个服务器,中转不同模块之间的`消息传递
  4. 外核
    • 外核可以提供一些高级的资源(未经抽象的资源)分配方式
    • 内核分配的资源都是抽象的,虚拟化的,比如虚拟地址,外核可以直接分配物理地址,在一些需要频繁跳跃的场景,外核直接分配一片连续空间效果会很好。当然,外核也负责保证安全。
    • 跳过虚拟步骤,就相当于跳过了映射层,可以提高效率,缺点是复杂。

OS引导

在这里插入图片描述

简单来说,就是开机扫ROM就可以把操作系统拉起来,但是具体还是要分几步走:

  1. 扫ROM,启动BIOS,自检
  2. 读磁盘的MBR,获取分区
  3. 从活动分区(C盘)中读PBR,获取C盘根目录
  4. 通过目录找到操作系统的程序,拉到内存中,完成OS启动

这四步环环相扣,前一个获取了信息,后一步才能根据此信息行动。

而第4步用的程序,位置一般在C:/Windows/Boot/下面。

虚拟机

在这里插入图片描述

  1. 第一类VMM,相当于传统OS的加强版,直接运行在硬件上
    • 虚拟OS看起来像一个OS,也有内核,但是实际上还是用户态,因此一个特权指令实际上要经过一次虚拟的系统调用+一次真正的系统调用。
    • 迁移性差,因为直接和硬件耦合
  2. 第二类VMM,是寄居在宿主OS之上的,分为两部分
    • 用户态的VMM和宿主的应用程序是共存的
    • 核心态的VMM是以驱动的形式存在的,持续运行在内核态

在这里插入图片描述

进程和线程

进程和线程基础

进程

在这里插入图片描述

PCB,记录进程元数据:

  1. 描述信息。用于区分进程,PID,UID
  2. 进程控制和管理信息。和进程运行状态有关
  3. 资源分配清单。
    • 资源是进程外部的,而数据段是程序产生的内部数据
  4. 处理器相关信息。寄存器上下文

进程特征:

  1. 并发性和异步是一起的
  2. 结构性指的是每个进程的结构都一样,都是PCB+数据段+程序段

进程状态

在这里插入图片描述

进程控制

在这里插入图片描述

在这里插入图片描述

创建原语分为4步:

  1. PCB创建和初始化
  2. 分配资源(此时进入就绪态)
  3. 插入就绪队列

撤销是逆过程:

  1. 剥夺所有资源,清理子进程
  2. 删除PCB

在这里插入图片描述

阻塞和唤醒,是可逆的过程

  1. 修改PCB:可逆,所以现场要保护起来
  2. 切换队列:把PCB放到对应队列中

无论是阻塞还是进程切换,都要剥夺CPU,而进程有一些内容还存在寄存器中,这些寄存器上下文就是保护现场要做的工作,是中断隐指令的内容。

在这里插入图片描述

进程通信

在这里插入图片描述

  1. 共享储存
    • 把两个进程的虚拟储存,映射到同一个物理储存区域
    • 因此要互斥访问
  2. 消息传递
    • 每一个进程都有一个消息队列
    • 直接通信:A进程把消息直接挂到B进程消息队列里
    • 间接通信:以信箱为中介,B要主动去信箱取出A发来的消息
  3. 管道通信
    • 联系生产者消费者,管道其实就是一个循环队列,是个内存缓冲区
    • 管道互斥访问,因此是半双工(像水管)

线程

在这里插入图片描述

在这里插入图片描述

  1. TCB:Thread CB
  2. 一个进程内部,线程之间资源共享
    • 因此切换成本很小,其就是为了频繁切换,提高并发性而生的。
  3. 一个程序的多线程可以放到不同进程中
    • 多核CPU的超线程
    • 但是这样就无法共享资源了,各用个的

在这里插入图片描述

线程可以理解为剥离掉公用资源后,剩下的相互独立的部分

因此线程的内容比较少,切换的时候只需要保证TCB里面的一些寄存器上下文就可以,比进程少很多。

线程实现

在这里插入图片描述

在这里插入图片描述

用户级线程,适用于早期OS没有线程管理功能的时候:

  1. 本质上是用户自己用代码(线程库)管理线程的调度
    • 在OS看来,只有一个进程而已
    • 线程的调度是纯用户态行为,这种调度非常简单(线程库的逻辑)
  2. 优缺点
    • 优:不需要系统调用,高效
    • 缺:假线程,代码在一个线程卡住,实际上都卡住了

在这里插入图片描述

内核级线程,这是经典的OS负责的线程:

  1. 优点:真并发
  2. 缺点:核心压力大

因此内核级线程又分出多种模式:

  1. 一对一
    • 这其实和内核级线程一样
  2. 多对一:多个用户级线程对应一个内核线程,而CPU只能看到内核线程
    • 这个模式比较鸡肋,和用户级线程一样
  3. 多对多:多个用户级线程,映射到多个内核线程
    • 这才是真神
    • 可以把用户线程切分成3块,每一块都用多对一模型映射到一个线程,整体上三个部分有序工作,互相之间不会拖累,兼顾了效率和并发性

在这里插入图片描述

CPU调度

调度的层次

在这里插入图片描述

作业调度,作业≈一个程序,储存的位置是外存,作业调度≈程序启动
低级调度,针对进程,切换CPU

中级调度,和作业调度一样都是在内外存之间的,区别如下:

  1. 作业调度是比较彻底,就是启动和终止
  2. 中级调度类似于休眠(挂起),暂时放到外存(手机的扩展内存技术就是这样实现的)
    • 引入7状态模型,对就绪和阻塞分别增加对应的挂起状态
    • 在挂起状态(外存里),也可以实现阻塞到就绪的转变
    • 从运行态可以跳过就绪态,直接跳到挂起

在这里插入图片描述

进程调度细节

在这里插入图片描述
进程调度时机:

  1. 主动
  2. 被动。说白了就是被抢占
    • 中断处理(中断隐指令)和原子操作,都会关中断,因此不会被打断
    • OS内核处理内核临界区的时候,权限高,不可被打断

区分一下:

  1. 狭义进程调度。在CPU空闲的时候,抓一个就绪态进程激活
  2. 进程切换。剥夺一个运行的进程,换成另外一个进程
    • 两个操作都要恢复新现场
    • 相比于调度,切换额外要做的操作是保护旧现场

广义的进程调度,可能包含了进程切换这一过程

在这里插入图片描述

最后提一嘴调度程序,我们说,调度是由OS控制的,本质上就是软件,那么说白了,负责调度的管理者,还是一个程序。

这个程序什么时候会运行呢?

  1. 如果是非抢占的时候,就是异步的运行,在特殊情况才运行(创销,阻塞唤醒)
  2. 抢占式的,那么就要定期巡查,决定一个CPU是否应该抢占

调度算法

评价指标

在这里插入图片描述

  1. 周转时间=等待+处理时间
  2. 带权周转时间
    • 本质上是个比例值,可以衡量等待时间在周转时间中的占比
    • 越大,则等待越久
  3. 等待时间。
    • 执行之前的时间,执行起来后等IO的时间不算
    • 作业的等待时间是在成为进程之前的那段时间
    • 进程的等待时间就是创建态+就绪态的那段时间
  4. 响应时间
    • 和等待时间类似,但是针对的只是一种请求,比如键盘,鼠标
批处理调度算法

在这里插入图片描述

在这里插入图片描述

对于非纯计算程序,IO时间不算等待,因此还要抛去IO操作的部分。

FCFS(其实就是FIFO),之所以对短作业不利,就是因为短作业的带权周转时间会很大,这代表其体验很差。

加粗样式

短=Short,即SJF,SPF

具体计算,要分为三部分:

  1. 还没来的作业
  2. 作业池中的作业
  3. 正在运行的作业

正在运行的作业只能在作业池中挑选,而不能是还没有进入作业池的,因此第一个任务只能是P1,即使他时间很长。

SJF分两种:

  1. 非抢占式的SJF如上
    • 比较简单,顺序操作
    • 只需要在作业完成时,分析作业池即可
  2. 抢占式的SJF(SRTN
    • 如果有一个新的作业来了,那么就有可能比当前正在运行的作业的剩余时间短,此时就把作业替换回作业池中(记得标注剩余时间)
    • 具体做题的时候,比非抢占式要额外多分析新作业来的时间点

在这里插入图片描述

  1. 题目区分细节
    • 默认非抢占,但是比较模糊
    • 考虑到抢占,SRTN的平均周转时间肯定是最少的
    • 如果默认作业没有到达顺序的先后之分,那么非抢占SJF=SRTN
  2. SJF对长作业不利,无论是否抢占,都可能造成饥饿现象

在这里插入图片描述

HRRN用到响应比指标,综合了等待时间和处理时间,在保证了优先级的前提下,修复了SJF饥饿的问题。

分析思路和SJF类似,都是分成三部分,HRRN为非抢占式的,所以只在CPU空闲的时候对作业池进行分析。

注意,其等待时间是从到达开始计数的。

交互式调度方法

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

RR(时间片轮转)

  1. 轮转本身很简单
    • 建立一个就绪队列,每一个时间片出队,处理队头对应的进程
    • 时间片完了以后就插到队尾
  2. 难在新任务来的时候,会改变队列结构
    • 新任务来了,也是插在队尾
    • 如果A任务的时间片完了,此时B任务刚来,这二者的顺序以B为先,毕竟新来的要照顾一下(注意,这个照顾顺序只针对想要同时入队的两个任务,前面早就在队里的任务仍然在前面)
  3. 如果任务处理完,时间片还没用完,会直接终止当前时间片
    • 很正常很人性化的设计,干等着没意思

因此,整个分析过程需要考虑的也是处理完以及新任务刚来的两种时刻。

严格来说,RR不会剥夺正在执行的时间片,但是先来先插到队尾的这种逻辑,以及规定时间片用完就剥夺,这两个操作具有抢占性,所以我们规定RR是抢占式的(剥夺的来源是时间片本身,而不是其他进程)

时间片太大,就会退化为FCFS,太小则切换开销占时间片的比例就太大了(类似于流水线那个感觉),效率降低。

在这里插入图片描述

优先级调度算法。优先数越高,就越排在前面激活。

此方法分为抢占式和非抢占式。
分析节点参考SJF。

在这里插入图片描述

多级反馈队列调度,这个是666,真神

我们直接分析一下其性质,相当复杂,但是又相当合理:

  1. 队列内部是RR,队列之间是抢占
  2. 关于优先级
    • 新手保护:刚来的,优先级最高
    • 耗时降级:如果耗时长,每完整执行一个时间片,优先级就会降低一级,直到降无可降
    • 被剥夺不降级:被剥夺严格来说不算执行完一个时间片,因此不降级,只是按RR原则放到了队尾。不过还会有补偿,新获得的时间片又是一个完整的时间片
  3. 关于轮转
    • 优先高级:高一级的队列为空,才对下一级进行RR遍历(有抢占性,如果高一级来了新的,则立马切到高一级)
    • 保障低级:越低级,时间片越长。虽然低优先级低人一等,但是总得让人家执行完,所以低优先级的时间片反而会更多,一旦轮到了,就可以持续执行很长时间(当然,如果你不争气,执行不完那就继续降级,又或者被强占,总之还是低人一等)

优缺点分析:

  1. 公平:FCFS
  2. 快响应:RR+优先级调度
  3. 短进程优先:SPF
  4. 自动优先级
    • 如果想要保证任务的高优先级,可以尽量让其不降级,比如如果进程因为IO主动放弃时间片,此时我们不认为其执行完毕,因此不降级,这样就保证了IO的高优先级
  5. 缺点:仍然不是绝对公平,因此会造成饥饿

在具体实践中,为了防止饥饿出现,可能一个队列会分配固定的时间上限,如果超过这个界限,还是要切换队列的,不能一直卡在高优先级队列。
此外,不同队列内部的策略还可以不一样。

在这里插入图片描述

同步与互斥

基本概念

在这里插入图片描述

异步就是无序性
同步就是有序性,A一定在B前。

遵循的原则,总结起来就是,忙可以先等一下,等久了就撤(让权),但是你不能让我等太久,过一段时间我还得拿回权利并且进入临界区。

互斥

互斥软件实现

在这里插入图片描述
在这里插入图片描述

单标志法是最原始的轮询

本质上,turn代表谦让以及指定,刚开始就指定一个进程,而一个进程执行完以后又会指定另外一个进程。
但是其问题在于,临界区使用权和CPU占用权是分裂的,让给你用,并不代表你就能用,即空闲也进不去,违背“空闲让进”

比如此时标记0进程能用临界区,但是此时CPU时间片属于1,此时while循环就会持续1个时间片,一边是忙等,另一边是空闲没人用

在这里插入图片描述

双标志法,把谦让逻辑变成了,将指定变成了排他逻辑,占用逻辑。

占用和释放,只修改自己的占用标记,不去指定他人。

双标志先检查,检查和上锁不连贯,此时,按照1526顺序,A还没上锁,B就通过检查了,就会同时进入临界区,即“忙”也能进去,违反了忙则等待。

为了修正,出现了双标志后检查法,这种方法先把临界区标记了,再检查,那么就可以确保别人拿不到临界区(缺德做法),但是这很明显不靠谱,会出现都用不上的情况,按照1526顺序,AB都标记,则会排他,那么AB就都会卡在检查阶段。

此时,即使临界区空闲,AB谁也不让着谁,谁也用不上,这违背了“空闲让进”,而且一直卡死,违背了“有限等待”

在这里插入图片描述

在这里插入图片描述

peterson算法,综合了单标志和双标志后检查法

标志代表意愿,turn代表谦让,最后被谦让的那一个,就可以获得使用权。

以1627举例,2先谦让一下,但是7后面有谦让一下,于是2就勉为其难的进入了,和现实的套路一模一样。
本质上,turn同一时间有且只能有一个值,因此同一时间只能有一个进程跳出循环,且必有一个进程跳出循环。

非常牛逼的思路,但是仍然优缺点,因为进程仍然是忙等状态,即违反了“让权等待”,但是已经是成本最低的了,这个操作可以通过时间片轮转来剥夺。

互斥硬件实现

在这里插入图片描述
关中断的缺点:

  1. 多处理机,关不了其他CPU,进程可以借助其他CPU访问临界
  2. 仅内核。因为这个操作给用户太危险

在这里插入图片描述

TestSet的操作,说白了就是用old检查,并对lock进行上锁,这是一个原子过程,检查和上锁是一气呵成的。
如果lock原来就是true,那么再上也无所谓
如果lock原来是false,那么就可以同时实现上锁+退出循环,不用担心被打断

上面这个代码只是模拟,实际上是硬件TSL指令实现的,是原子的,而软件编程是无法达到这个效果的。
缺点和peterson一样,都是忙等,不满足“让权等待”原则

还有一个Swap指令(Exchange,XCHG指令),和TSL基本一样的逻辑和特性

互斥锁(自旋锁)

互斥锁是一种思想,和mutex操作很像,就是申请和释放。

但是其申请过程是忙等的,所以TSL,swap指令都是自旋锁,单标指法其实也是自旋锁,申请过程都具有原子性

当然,正如单标志法哪里说的,忙等其实不完全忙等,时间片没了就退出(单处理器没有RR,所以就是彻底忙等)。甚至说有时候反而有意外效果,等待的时候不用切换上下文,有时候成本反而低。

在这里插入图片描述

信号量

信号量机制

在这里插入图片描述

整形信号量,说白了就是双标志先检查,但是P和V是原语,可以保证不会同时进入

但是因为底层还是一个循环,仍然会忙等,不满足让权等待。

在这里插入图片描述

记录型信号量引入阻塞队列,解决了忙等现象

  1. 原来是忙等,现在发现资源不够就丢到阻塞队列里。
    • 极限情况为0,-1后为负,此时是第一个进程阻塞
  2. 如果资源够了,且阻塞队列里有进程,就唤醒
    • 极限情况为-1,+1后为0,此时把阻塞队列里最后一个进程唤醒
信号量实现互斥同步

在这里插入图片描述

semaphore mutex = 1 :代表记录型信号量,有等待队列

互斥比较简单,mutex=1,PV夹住临界区。

在这里插入图片描述

同步是前V后P,用一个信号量关联两个进程,等V操作执行完后,P才能执行下去。

给定一个拓扑图,只需要把每一个前驱后继关系都用一个信号量定义一下即可。
之后每一个节点都是一个进程,把边定义的前驱后继关系写到进程里面即可:

  1. 入边写P
  2. 出边写V

在这里插入图片描述

经典信号量问题

生产者消费者——基本的分析思路

在这里插入图片描述

需要注意一个细节就是,P操作是不可互换的,因为mutex只夹临界区,夹得多了就会出问题(死锁)
V操作可以互换,因为V操作一定不会被卡住

在这里插入图片描述

多生产者多消费者——多种生产者

在这里插入图片描述

首先是最简单的两组关系:

  1. apple和orange各自有一对同步关系
  2. plate关系:关键在于盘子,盘子是双方的一个中介,并不能单看父或者母,要把父母统一为一方,把子女统一为另一方
    在这里插入图片描述

具体实现如下,三个同步信号量,这里将plate设置为“还可以放的空间”,因此初值为1

因此,整体就实现了一个PV结构,每一个进程,都是有P有V。
mutex实际上可有可无,因为我们这里的资源上限为1,已经相当于mutex的作用了,但是如果盘子空间变成2,就得加mutex了,否则就可能发生覆盖现象。

在这里插入图片描述

如果反过来呢,plate=盘中可用水果数量,会出问题,比如dad,此时就是V(apple),V(plate),可以看到这个进程是没有P的,也就是说不会被阻塞,他可以一直释放。

所以我们这里还可以总结出一条生产者消费者问题中,隐性的要求,就是PV一定是要成环的,相互制约,一个进程只有V无P,必然是有问题的,在我们制定信号量意义的时候,也应该考虑构造一个PV环结构。

吸烟者问题——多功能生产者

在这里插入图片描述

一个多功能生产者,给多个单功能消费者提供原料,同步关系如下

在这里插入图片描述

再拓展一下思路,如果finish定义为1呢?

那么就要把生产者的P操作放在最开始,消费者是不变的,仍然可以正常运行(因为仍然是PV环,而且PV关系没有变)

分析一下是否需要mutex,因为只有一个生产者,所以缓冲区最多有1个元素,不会出问题。
但是呢,如果有n生产者,此时因为生产者是V在前的,第一次生产不受阻塞,所以就可能会让缓冲区里存在n个元素,所以这种写法其实不好,如果是按照我那个P在前的写法,即使是有多个生产者进程,只要规定finish=1,就只能有一个元素被生产

哲学家进餐问题——连续申请多个资源

这个问题本身不难,难在如何解决死锁。

哲学家进餐问题的死锁情况为,每个哲学家都只P了一半,都卡在了第二个P上。
本质上,哲学家进餐是连续申请多个资源,如果申请的途中被卡了,而且是集体卡顿,那就死锁了。

所以解决哲学家死锁,就要从这些领域入手:

  1. 最多让n-1个哲学家同时进餐,这样就一定可以保证有1个哲学家不会被卡死
    • 可以用一个值为n-1的信号量限制
  2. 限定哲学家拿资源的顺序,强制哲学家进行两两竞争
    • 比如指定奇数哲学家先左边的,偶数先拿右边的,那么这一对哲学家必然是两个必有一个阻塞,而另一个没被阻塞的哲学家,在另一边不存在竞争,一定可以吃到
  3. 保证哲学家多个P操作的原子性
    • 在一连串P外面加个mutex即可
    • 即使一个哲学家被卡,其他哲学家也不可能是P操作被卡,即其他哲学家在吃饭,这是暂时的,可以恢复的

在这里插入图片描述

读者写者问题

死锁

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1298934.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python 云服务器应用,Https,定时重启

Python 云服务器应用,Https,定时重启 环境搭建Python模块模块导入生成Flask实例GET处理启动服务器打开网页验证 GET接入证书 支持https申请证书下载证书保留 xxx.crt 和 xxx.key文件就可以了 copy到python项目目录ssl_context 配置 宝塔面板操作在www目录下新建python工作目录在…

大作文:图画(06:偶像崇拜)

题目 第一段 第二段 第三段 第四段

蓝桥小白赛1

👩‍🏫 地址 1. 蘑菇炸弹 👩‍🏫 蘑菇炸弹 🎉 AC code import java.util.Scanner;public class Main {public static void main(String[] args){Scanner sc new Scanner(System.in);int n sc.nextInt();int[] a …

STM32F407-14.3.9-02输出比较模式

输出比较模式 输出比较模式生成波形时 当采用上升沿或下降沿计数时,更改ARR的值可改变周期; 更改CCRx的值会影响到生成波形的相位。波形的占空比永远50% 当采用中心对齐模式时, 更改ARR的值可以改变周期,更改CCRx的值可以改…

【每日一题】【面试经典150 | 动态规划】爬楼梯

Tag 【动态规划】【数组】 题目来源 70. 爬楼梯 题目解读 有过刷题「动态规划」刷题经验的读者都知道,爬楼梯问题是一种最典型也是最简单的动态规划问题了。 题目描述为:你每次可以爬 1 或者 2 个台阶,问爬上 n 阶有多少种方式。 解题思路…

Ubuntu上安装 Git

在 Ubuntu 上安装 Git 可以通过包管理器 apt 进行。以下是在 Ubuntu 上安装 Git 的步骤: 打开终端。你可以按 Ctrl Alt T 组合键来打开终端。 运行以下命令以确保你的系统的软件包列表是最新的: sudo apt update 安装 Git: sudo apt inst…

C/C++,贪婪算法——博鲁夫卡算法(Boruvka)的计算方法与源程序

1 文本格式 // Boruvkas algorithm to find Minimum Spanning // Tree of a given connected, undirected and // weighted graph #include <stdio.h> // a structure to represent a weighted edge in graph struct Edge { int src, dest, weight; }; // a struc…

Leetcode刷题详解——字符串相加

1. 题目链接&#xff1a;415. 字符串相加 2. 题目描述&#xff1a; 给定两个字符串形式的非负整数 num1 和num2 &#xff0c;计算它们的和并同样以字符串形式返回。 你不能使用任何內建的用于处理大整数的库&#xff08;比如 BigInteger&#xff09;&#xff0c; 也不能直接将…

python格式化内容

1.字符串格式化: 定义列表 [{"姓名": "张三", "年龄": 18, "性别": "男"}, {"姓名": "里斯李四李斯", "年龄": 18, "性别": "男"}, {"姓名": "斯托夫斯基…

HarmonyOS--ArkTS(1)--基本语法(1)

目录 基本语法概述 声明式UI描述 自定义组件 创建自定义组件 自定义组件的结构--struct &#xff0c;Component&#xff0c;build()函数 生命周期 基本语法概述 装饰器&#xff1a; 用于装饰类、结构、方法以及变量&#xff0c;并赋予其特殊的含义。如上述示例中Entry、C…

[ROS2] --- 通信接口

1 通信接口的定义 通信并不是一个人自言自语&#xff0c;而是两个甚至更多个人&#xff0c;你来我往的交流&#xff0c;交流的内容是什么呢&#xff1f;为了让大家都好理解&#xff0c;我们可以给传递的数据定义一个标准的结构&#xff0c;这就是通信接口。 ROS的通信系统&am…

CleanMyMac X2024免费许可证(激活教程)

CleanMyMac X是一款流行的系统优化工具&#xff0c;专为Mac用户设计。它可以帮助用户清理Mac系统中的垃圾文件、卸载不需要的程序、加速Mac性能以及保护Mac系统的安全。 一、简介 CleanMyMac X是一款功能强大的系统优化工具&#xff0c;它可以帮助用户清理Mac系统中的垃圾文件…

时间序列预测 — GRU实现多变量多步光伏预测(Tensorflow)

目录 1 数据处理 1.1 数据集简介 1.2 导入库文件 1.3 数据集处理 1.4 训练数据构造 2 模型训练与预测 2.1 模型训练 2.2 模型多步预测 2.3 预测可视化 1 数据处理 1.1 数据集简介 实验数据集采用数据集7&#xff1a;常州普利司通光伏数据集&#xff08;下载链接&…

C语言精选——选择题Day41

第一题 1. 有以下程序段&#xff1a; char *p, *q; p (char *)malloc(sizeof(char) * 20); q p; scanf("%s %s", p, q); printf("%s %s\n", p, q); 若从键盘输入&#xff1a;abc def↙&#xff0c;则输出结果是&#xff08; &#xff09; A&#xff1a;d…

系统架构设计师教程(一)绪论

系统架构设计师 1.1 系统架构概述1.1.1 系统架构的定义及发展历程1.1.2 软件架构的常用分类及建模方法1、软件架构常用分类2、系统架构的常用建模方法 1.2 系统架构设计师概述1.3 如何成为一名好的系统架构设计师 1.1 系统架构概述 自1946年第一台计算机诞生以来&#xff0c;计…

【C语言】函数调用及创建,并将数组传参到函数

&#x1f3a5; 岁月失语唯石能言的个人主页 &#x1f525;个人栏专&#xff1a;秒懂C语言 ⭐若在许我少年时&#xff0c;一两黄金一两风 目录 前言 一、函数的概念 二、库函数 2.1 标准库和头文件 2.2库函数的使用方法 2.2.1功能 2.2.2库函数的头文件 2.2…

看图学源码之 Atomic 类源码浅析二(cas + 分治思想的原子累加器)

原子累加器 相较于上一节看图学源码 之 Atomic 类源码浅析一&#xff08;cas 自旋操作的 AtomicXXX原子类&#xff09;说的的原子类&#xff0c;原子累加器的效率会更高 XXXXAdder 和 XXXAccumulator 区别就是 Adder只有add 方法&#xff0c;Accumulator是可以进行自定义运算方…

Redis如何做内存优化?

Redis如何做内存优化&#xff1f; 1、缩短键值的长度 缩短值的长度才是关键&#xff0c;如果值是一个大的业务对象&#xff0c;可以将对象序列化成二进制数组&#xff1b; 首先应该在业务上进行精简&#xff0c;去掉不必要的属性&#xff0c;避免存储一些没用的数据&#xff1…

idea__SpringBoot微服务07——Thymeleaf

Thymeleaf 一、Thymeleaf入门二、Thymeleaf语法————————创作不易&#xff0c;如觉不错&#xff0c;随手点赞&#xff0c;关注&#xff0c;收藏(*&#xffe3;︶&#xffe3;)&#xff0c;谢谢~~ 新依赖&#xff1a;Thymeleaf的 <!--thymeleaf--> <dependency…

uniapp生成条形码?

首先先在插件市场找到条形码 链接&#xff1a;https://ext.dcloud.net.cn/search?q 下载到项目里面 三、在pages.json中写入以下&#xff1a; 四、在html页面 这样就已经差不多了 条形码可以出来了