筑基系列-操作系统基础知识小抄版
计算机基础知识筑基三部曲:
- 包括发展史、CPU、总线、存储器、指令系统、控制器、运算器、位运算等
- 包括进程与线程同步管理、作业管理、存储管理、虚拟内存、Linux、文件管理等
- 包括OSI七层模型各层详解、IP协议、TCP\IP协议、Http协议、DNS协议等
目录
1 操作系统概览
1.1 什么是操作系统
- 管理配置内存、决定资源供需顺序、控制输入输出设备等
- 操作系统是管理计算机硬件和软件资源的计算机程序
- 操作系统提供让用户和系统交互的操作界面
- 从手机到超级计算机,操作系统可简单也可复杂
- 操作系统的种类是多种多样的,不局限于计算机
- 在不同的设备上,操作系统可向用户呈现多种操作手段
- Android,IOS,HarmonyOS
- Windows ,Linux ,MacOS
- 总结:管理硬件、提供用户交互的软件系统
1.2 为什么需要操作系统
- 我们不可能直接操作计算机硬件
- 设备种类繁多复杂,需要统一界面
- 设备种类繁多复杂,需要统一界面
1.3 操作系统的基本功能
- 操作系统统一管理着计算机资源
- 处理器资源
- IO设备资源
- 存储器资源
- 文件资源
- 操作系统实现了对计算机资源的抽象
- IO设备管理软件,提供读写接口
- 用户无需面向硬件接口编程
- 文件管理软件,提供操作文件接口
- 操作系统提供了用户与计算机之间的接口
- 命令形式
- 图像窗口形式
- 系统调用形式
1.4 操作系统相关概念
- 并发性/并行性
- 多道程序设计
- 多道程序设计是指在计算机内存中同时存放多个程序
- 多道程序在计算机的管理程序之下相互穿插运行
- 并行是指两个或多个事件可以在同一个时刻发生
- 并发是指两个或多个事件可以在同一个时间间隔发生
- 多道程序设计
- 共享性
- 共享性表现为操作系统中的资源可供多个并发的程序共同使用
- 这种共同使用的形式称之为资源共享
- 多个程序可以同时使用主存资源
- 资源共享根据属性可分为两种方式
- 互斥共享形式
- 当资源被程序A占用时,其他想使用的话只能等待
- 只有进程A使用完以后,其他进程才可以使用该资源
- 打印机
- 同时访问形式
- 某种资源在一段时间内并发地被多个程序访问
- 这种“同时”是宏观的,从宏观去看该资源可以被同时访问
- 向磁盘写数据
- 互斥共享形式
- 虚拟性
- 虚拟性表现为把一个物理实体转变为若干个逻辑实体
- 物理实体是真实存在的,逻辑实体是虚拟的
- 虚拟的技术主要有时分复用技术和空分复用技术
- 时分复用技术
- 资源在时间上进行复用,不同程序并发使用
- 多道程序分时使用计算机的硬件资源
- 提高资源的利用率
- 虚拟处理器技术
- 借助多道程序设计技术
- 为每个程序建立进程
- 多个程序分时复用处理器
- 虚拟设备技术
- 物理设备虚拟为多个逻辑设备
- 每个程序占用一个逻辑设备
- 多个程序通过逻辑设备并发访问
- 空分复用技术
- 空分复用技术用来实现虚拟磁盘、虚拟内存等
- 提高资源的利用率,提升编程效率
- 虚拟磁盘技术
- 物理磁盘虚拟为逻辑磁盘
- C、 D、 E等逻辑盘
- 使用起来更加安全、方便
- 虚拟内存技术
- 在逻辑上扩大程序的存储容量
- 使用比实际内存更大的容量
- 大大提升编程效率
- 异步性
- 在多道程序环境下,允许多个进程并发执行
- 进程在使用资源时可能需要等待或放弃
- 进程的执行并不是一气呵成的,而是以走走停停的形式推进
- 进程以不可预知的速度向前推进
2.进程管理
2.1 进程概述
为什么需要进程
- 没有配置OS之前,资源属于当前运行的程序
- 配置OS之后,引入多道程序设计的概念
- 合理的隔离资源、运行环境,提升资源利用率
- 进程是系统进行资源分配和调度的基本单位
- 进程作为程序独立运行的载体保障程序正常执行
- 进程的存在使得操作系统资源的利用率大幅提升
主存中的进程形态-进程控制块(PCB)
- 用于描述和控制进程运行的通用数据结构
- 记录进程当前状态和控制进程运行的全部信息
- PCB的使得进程是能够独立运行的基本单位
- PCB是操作系统进行调度经常会被读取的信息
- PCB是常驻内存的,存放在系统专门开辟的PCB区域内
- 标识符
- 标识符唯一标记一个进程,用于区别其他进程
- 状态
- 标记进程的进程状态,如:运行态
- 优先级
- 程序计数器
- 进程即将被执行的下一条指令的地址
- 内存指针
- 程序代码、进程数据相关指针
- 上下文数据
- 进程执行时处理器存储的数据
- IO状态信息
- 被进程IO操作所占用的文件列表
- 记账信息
- 使用处理器时间、时钟数总和等
进程与线程
- 关系
- 一个进程可以有一个或多个线程
- 进程是系统进行资源分配和调度的基本单位
- 线程是操作系统进行运行调度的最小单位
- 包含在进程之中,是进程中实际运行工作的单位
- 一个进程可以并发多个线程,每个线程执行不同的任务
- 进程的线程共享进程资源
- 区别
进程 线程 资源 资源分配的基本单位 不拥有资源 调度 独立调度的基本单位 独立调度的最小单位 系统开销 进程系统开销大 线程系统开销小 通信 进程IPC 读写同一进程数据通信 - 关系
2.2 进程管理五状态模型
- 就绪状态
- 当进程被分配到除CPU以外所有必要的资源后
- 只要再获得CPU的使用权,就可以立即运行
- 其他资源都准备好、只差CPU资源的状态为就绪状态
- 就绪队列:在一个系统中多个处于就绪状态的进程通常排成一个队列
- 阻塞状态
- 进程因某种原因如:其他设备未就绪而无法继续执行
- 从而放弃CPU的状态称为阻塞状态
- 阻塞队列
- 执行状态
- 进程获得CPU,其程序正在执行称为执行状态
- 在单处理机中,在某个时刻只能有一个进程是处于执行状态
- 创建状态
- 分配PCB—> 插入就绪队列
- 创建进程时拥有PCB但其他资源尚未就绪的状态称为创建状态
- 操作系统提供fork函数接口创建进程
- 终止状态
- 系统清理 —>PCB归还
- 进程结束由系统清理或者归还PCB的状态称为终止状态
2.3 进程同步
为什么需要进程间同步
生产者-消费者问题
- 生产者进程将生产的产品提供给消费者进程进行消费
- 生产者进程和消费者进程可以并发执行
- 在两者之间设置了一个具有n个缓冲区的缓冲池
- 生产者将产品缓冲区中,消费者进程从缓冲区取走产品消费
- 单从生产者程序或消费者程序去看是没问题的
- 单两者并发执行时就可能出差错
- 临界资源:缓存区
哲学家进餐问题
- 有五个哲学家,他们的生活方式是交替地进行思考和进餐
- 哲学家们共同使用一张圆桌,分别坐在周围的五张椅子上
- 在圆桌上有五个碗和五支筷子。平时哲学家们只进行思考,饥饿时则试图取靠近他们的左、右两支筷子
- 只有两支筷子都被他拿到的时候才能进餐
- 进餐完毕之后,放下左右筷子继续思考
- 五个哲学家同时拿起左边筷子
- 五个哲学家都等待右边筷子释放
- 五个哲学家饿死
- 临界资源:筷子
问题的根源
- 根源问题是:彼此相互之间没有通信
- 如果生产者通知消费者我已经完成一件生产
- 哲学家向旁边哲学家说我要进餐了
进程同步的目的
- 对竞争资源在多进程间进行使用次序的协调
- 使得并发执行的多个进程之间可以有效使用资源和相互合作
临界资源
- 临界资源指的是一些虽作为共享资源却又无法同时被多个线程共同访问的共享资源。
- 当有进程在使用临界资源时,其他进程必须依据操作系统的同步机制等待占用进程释放该共享资源才可重新竞争使
用共享资源。
进程间同步的原则
- 空闲让进:资源无占用,允许使用
- 忙则等待:资源有占用,请求进程等待
- 有限等待:保证有限等待时间能够使用资源
- 让权等待:等待时,进程需要让出CPU
进程间同步的方法
- 消息队列
- 共享存储
- 信号量
线程同步
- 进程的线程共享进程资源
- 当多个线程并发使用进程资源时,也需要同步
- 线程间同步的方法
- 互斥量
- 读写锁
- 自旋锁
- 条件变量
2.4 Linux的进程管理
进程的类型
- 前台进程
- 前台进程就是具有终端,可以和用户交互的进程
- 后台进程
- 与前台进程相对,没有占用终端的就是后台进程
- 后台程序基本上不和用户交互,优先级比前台进程低
- 将需要执行的命令以“&”符号结束
- 守护进程
- 守护(daemon)进程是特殊的后台进程
- 很多守护进程在系统引导的时候启动,一直运行直到系统关闭
- Linux有很多典型的守护进程
- 进程名字以“d”结尾的一般都是守护进程
- crond
- httpd
- sshd
- mysqld
- 前台进程
进程的标记
进程ID
- 进程ID是进程的唯一标记,每个进程拥有不同的ID
- 进程ID表现为一个非负整数,最大值由操作系统限定
- top命令查看系统中的所有进程信息
- ID为0的进程为idle进程,是系统创建的第一个进程
- ID为1的进程为init进程,是0号进程的子进程,完成系统初始化
- Init进程是所有用户进程的祖先进程
进程的状态标记
- man ps 命令查看用户命令帮助文档
状态符号 状态说明 R (TASK_RUNNING),进程正处于运行状态 S (TASK_INTERRUPTIBLE),进程正处于睡眠状态 D (TASK_UNINTERRUPTIBLE),进程正在处于IO等待的睡眠状态 T (TASK_STOPPED),进程正处于暂停状态 Z (TASK_DEAD or EXIT_ZOMBIE),进程正处于退出状态,或僵尸进程 父子进程
- 操作系统提供fork函数接口创建进程
- 父子进程关系:进程A调用fork函数创建进程B,进程A就是进程B的父进程
- 父子进程关系可以通过pstree命令查看
操作进程的相关命令
- ps命令
- ps命令常用于显示当前进程的状态
- ps命令常配合aux参数或ef参数和grep命令检索特定进程
- jobs
- 只有(SIGKILL 9)信号可以无条件终止进程,其他信号进程有权忽略
- nohup
- 不挂断地运行命令
- fg/bg命令
- fg命令将一个后台命令调换至前台终端继续执行
- bg命令将一个后台暂停的命令变成继续执行
- ctrl+z将前台工作暂停
- kill
- kill命令发送指定信号给进程
- kill –l 可以查看操作系统支持的信号
- 只有(SIGKILL 9)信号可以无条件终止进程,其他信号进程有权忽略
- ps命令
3.作业管理
3.1 进程调度
进程调度是指计算机通过决策决定哪个就绪进程可以获得CPU使用权
保留旧进程的运行信息,请出旧进程(收拾包袱)
选择新进程,准备运行环境并分配CPU(新进驻)
调度机制
- 就绪队列的委派机制
- 将就绪进程按照一定的方式排成队列,以便调度程序可以最快找到就绪进程
- 选择运行进程的委派机制
- 调度程序以一定的策略选择就绪进程,将CPU资源分配给它
- 新老进程的上下文切换机制
- 保存当前进程的上下文信息,装入被委派执行进程的运行上下文
- 老进程的上下文存入主存
- 新进程的上下文装载到高速缓存中
- 就绪队列的委派机制
调度方式
- 非抢占式的调度
- 处理器一旦分配给某个进程,就让该进程一直使用下去
- 调度程序不以任何原因抢占正在被使用的处理器
- 直到进程完成工作或因为IO阻塞才会让出处理器
- 抢占式的调度
- 允许调度程序以一定的策略暂停当前运行的进程
- 保存好旧进程的上下文信息,分配处理器给新进程
抢占式调度 抢占式调度 系统开销 频繁切换,开销大 切换次数少,开销小 公平性 相对公平 不公平 应用 通用系统 专用系统 - 非抢占式的调度
调度算法
- 先来先服务调度算法
- 从就绪队列按照顺序从队列头开始调度
- 短进程优先调度算法
- 调度程序优先选择就绪队列中估计运行时间最短的进程
- 短进程优先调度算法不利于长作业进程的执行
- 高优先权优先调度算法
- 进程附带优先权,调度程序优先选择权重高的进程
- 高优先权优先调度算法使得紧迫的任务可以优先处理
- 前台进程优先级高于后台进程
- 时间片轮转算法
- 按先来先服务的原则排列就绪进程
- 每次从队列头部取出待执行进程,分配一个时间片执行
- 是相对公平的调度算法,但不能保证及时响应用户
- 先来先服务调度算法
3.2 死锁
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
死锁的产生
基本原因
- 竞争资源
- 共享资源数量不满足各个进程需求
- 各个进程之间发生资源竞争导致死锁
- 进程调度顺序不当
- 调度顺序导致共享资源被多个进程互相持有无法释放,可以优先满足进程A的调度再调度B
- 竞争资源
必要条件
- 互斥条件
- 进程对资源的使用是排他性的使用
- 某资源只能由一个进程使用,其他进程需要使用只能等待
- 请求保持条件
- 进程至少保持一个资源,又提出新的资源请求
- 新资源被占用,请求被阻塞
- 被阻塞的进程不释放自己保持的资源
- 不可剥夺条件
- 进程获得的资源在未完成使用前不能被剥夺
- 获得的资源只能由进程自身释放
- 环路等待条件
- 发生死锁时,必然存在进程-资源环形链
- P1(R1)-> P2(R2)->P3(R3->)P4(R4) ->P1(R1)
- 互斥条件
死锁的处理
预防死锁的方法-破坏必要条件
- 摒弃请求保持条件
- 系统规定进程运行之前,一次性申请所有需要的资源
- 进程在运行期间不会提出资源请求,从而摒弃请求保持条件
- 摒弃不可剥夺条件
- 当一个进程请求新的资源得不到满足时,必须释放占有的资源
- 进程运行时占有的资源可以被释放,意味着可以被剥夺
- 摒弃环路等待条件
- 可用资源线性排序,申请必须按照需要递增申请
- 线性申请不再形成环路,从而摒弃了环路等待条件,A B C D E
- 摒弃请求保持条件
银行家算法
- 是一个可操作的著名的避免死锁的算法
- 以银行借贷系统分配策略为基础的算法
- 客户申请的贷款是有限的,每次申请需声明最大资金量
- 银行家在能够满足贷款时,都应该给用户贷款
- 客户在使用贷款后,能够及时归还贷款用来满足其它客户
- 已分配资源表
A B C D P1 0 0 1 4 P2 1 4 3 2 P3 1 3 5 4 P4 1 0 0 0 - 所需资源表
A B C D P1 0 6 5 6 P2 1 9 4 2 P3 1 3 5 6 P4 1 7 5 0 - 可分配资源表
A B C D - 1 5 2 0 - 还需分配资源表
- 通过可分配资源表看它能够满足哪一个进程所需就把可分配资源给谁,不满足的就不执行知道有资源能够满足任何一个为止
- 所以P2会先获得资源
A B C D P1 0 6 4 2 P2 0 5 1 0 P3 0 0 0 2 P4 0 7 5 0
4.存储管理
4.1 计算机进行存储管理的必要性
- 早期计算机编程并不需要过多的存储管理
- 随着计算机和程序越来越复杂,存储管理成为必要
- 确保计算机有足够的内存处理数据
- 确保程序可以从可用内存中获取一部分内存使用
- 确保程序可以归还使用后的内存以供其他程序使用
4.2 内存的分配过程
分配方法
单一连续分配
- 单一连续分配是最简单的内存分配方式
- 只能在单用户、单进程的操作系统中使用
- 分为系统区,用户区
固定分区分配
- 固定分区分配是支持多道程序的最简单存储分配方式
- 内存空间被划分为若干固定大小的区域
- 每个分区只提供给一个程序使用,互不干扰
动态分区分配(常用)
- 根据进程实际需要,动态分配内存空间
- 相关数据结构、分配算法
- 动态分区空闲表数据结构,1:已使用,0:未使用
分区 1 2 3 4 标记 0 1 1 0 - 动态分区空闲链数据结构
- 采用双向链表将内存块链接起来,连续的空闲区可以合并在一个链表节点里
- 节点需记录可存储的容量
- 动态分区分配算法
- 首次适应算法(FF算法)
- 分配内存时从开始顺序查找适合内存区
- 若没有合适的空闲区,则该次分配失败
- 每次从头部开始,使得头部地址空间不断被划分
- 循环适应算法,每次分配不从头开始,从上一次结束的地方开始分配
- 最佳适应算法(BF算法)
- 最佳适应算法要求空闲区链表按照容量大小排序
- 遍历空闲区链表找到最佳合适空闲区
- 快速适应算法(QF算法)
- 快速适应算法要求有多个空闲区链表
- 每个空闲区链表存储一种容量的空闲区
- 首次适应算法(FF算法)
4.3 内存的回收过程
- 存在回收内存的四种情况
- 回收区与空闲区链接在一起并且链接在后面
- 不需要新建空闲链表节点
- 只需要把空闲区1的容量增大为空闲区即可
- 回收区与空闲区链接在一起并且链接在前面
- 将回收区与空闲区合并
- 新的空闲区使用回收区的地址
- 回收区与空闲区链接在一起并且链接在中间
- 将空闲区1、空闲区2和回收区合并
- 新的空闲区使用空闲区1的地址
- 未链接空闲区,单一的回收区
- 为回收区创建新的空闲节点
- 插入到相应的空闲区链表中去
- 回收区与空闲区链接在一起并且链接在后面
4.4 进程的存储管理
页式存储管理
- 字块是相对物理设备的定义,页面则是相对逻辑空间的定义
- 将进程逻辑空间等分成若干大小的页面
- 相应的把物理内存空间分成与页面大小的物理块
- 以页面为单位把进程空间装进物理内存中分散的物理块
- 页面大小应该适中,过大难以分配,过小内存碎片过多
- 页面大小通常是512B~8K
- 页表:记录进程逻辑空间与物理空间的映射,表示为 [页面编号,字块编号]
- 页地址:[地址,页内偏移]
- 问题:现代计算机系统中,可以支持非常大的逻辑地址空间(2^32~2^64),这样,页表就变得非常大,要占用非常大的内存空间,如,具有32位逻辑地址空间的分页系统,规定页面大小为4KB,则在每个进程页表中的页表项可达1M(2^20)个,如果每个页表项占用1Byte,故每个进程仅仅页表就要占用1MB的内存空间
- 2^32/2^12=2^20=1M个页表项
- 多级页表:根页表的字块存的是子页表的地址,在运行时可以按需加载子页表
- 不足:有一段连续的逻辑分布在多个页面中,将大大降低执行效率
段式存储管理
- 将进程逻辑空间划分成若干段(非等分)
- 段的长度由连续逻辑的长度决定
- 主函数MAIN、子程序段X、子函数Y等
- 段表:[段号 ,基址. 段长]
- 段地址:[段号, 段内偏移]
页式存储管理与段式存储管理的对比
- 段式存储和页式存储都离散地管理了进程的逻辑空间
- 页是物理单位,段是逻辑单位
- 分页是为了合理利用空间,分段是满足用户要求
- 页大小由硬件固定,段长度可动态变化
- 页表信息是一维的,段表信息是二维的
段页式存储管理
- 分页可以有效提高内存利用率(虽然说存在页内碎片)
- 分段可以更好满足用户需求,因为逻辑可以通过用户来写
- 两者结合,形成段页式存储管理
- 先将逻辑空间按段式管理分成若干段
- 再把段内空间按页式管理等分成若干页
- 段页地址:[段号, 段内页号. 页内地址]
4.5 虚拟内存
- 虚拟内存概述
- 有些进程实际需要的内存很大,超过物理内存的容量
- 多道程序设计,使得每个进程可用物理内存更加稀缺
- 不可能无限增加物理内存,物理内存总有不够的时候
- 虚拟内存是操作系统内存管理的关键技术
- 使得多道程序运行和大程序运行成为现实
- 把程序使用内存划分,将部分暂时不使用的内存放置在辅存
- 虚拟内存实际是对物理内存的补充,速度接近于内存,成本接近于辅存
- 程序的局部性原理
- 局部性原理是指CPU访问存储器时,无论是存取指令还是存取数据,所访问的存储单元都趋于聚集在一个较小的连续区域中。
- 程序运行时,无需全部装入内存,装载部分即可
- 如果访问页不在内存,则发出缺页中断,发起页面置换
- 从用户层面看,程序拥有很大的空间,即是虚拟内存
- 虚拟内存的置换
- 替换策略发生在Cache-主存层次、主存-辅存层次
- Cache-主存层次的替换策略主要是为了解决速度问题
- 主存-辅存层次主要是为了解决容量问题
- 置换时机
- 高速缓存的替换时机
- 缓存没有数据,需要从主存载入所需数据
- 主存页面的替换时机
- 主存缺页,需要从辅存载入页面数据
- 高速缓存的替换时机
- 置换算法
- 先进先出算法(FIFO)
- 把主存看做是一个先进先出的队列
- 优先替换最先进入队列的字块
- 最不经常使用算法(LFU)
- 优先淘汰最不经常使用的字块
- 需要额外的空间记录字块的使用频率
- 最近最少使用算法(LRU)
- 优先淘汰一段时间内没有使用的字块
- 如果正在使用的字块在缓存就将其移到表头,保证链表头部节点是最近使用的
- 有多种实现方法,一般使用双向链表
- 先进先出算法(FIFO)
4.6 Linux的存储管理
页内碎片
- 内部碎片是已经被分配出去(能明确指出属于哪个进程)的内存空间大于请求所需的内存空间,不能被利用的内存空间就是内部碎片。
页外碎片
- 外部碎片是指还没有分配出去(不属于任何进程),但是由于大小而无法分配给申请内存空间的新进程的内存空闲块。
Buddy内存管理算法
- Buddy算法是经典的内存管理算法
- 算法基于计算机处理二进制的优势具有极高的效率
- 算法主要是为了解决内存外碎片的问题
- 实际是将内存外碎片问题 转移成内存内碎片问题
- 努力让内存分配与相邻内存合并能快速进行
- 内存分配原则
- 向上取整为2的幂大小
- 70k→128k
- 129k→256k
- 666k→1024k
- 伙伴系统
- “伙伴”指的是内存的“伙伴”
- 一片连续内存的“伙伴”是相邻的另一片大小一样的连续内存
- 分配过程
- 创建一系列空闲块链表,每一种都是2的幂
- 假设存储空间有1M大小,分配100k内存
- 100k向上取2的幂=128k
- 查询是否有128k空闲内存块?
- 没有!查询是否有256k空闲内存块?
- 没有!查询是否有512k空闲内存块?
- 没有!查询是否有1M空闲内存块?
- 有,摘下1M空闲内存块,分配出去
- 拆下512k放在512k的空闲链表,其余的分配出去
- 拆下256k放在256k的空闲链表,其余的分配出去
- 拆下128k放在128k的空闲链表,其余的分配出去
- 分配完毕
- 回收过程
- 判断刚才分配的内存伙伴在空闲链表上吗?
- 在!移除伙伴,合并为256k空闲内存,判断
- 在!移除伙伴,合并为512k空闲内存,判断
- 在!移除伙伴,合并为1M空闲内存
- 插入1M空闲链表,回收完成
Linux交换空间
- 交换空间(Swap)是磁盘的一个分区
- Linux物理内存满时,会把一些内存交换至Swap空间
- Swap空间是初始化系统时配置的
- top命令可以查看交换空间的分配情况
- 主要用途:
- 冷启动内存依赖
- 系统睡眠依赖
- 大进程空间依赖
- 交换空间VS虚拟内存
- Swap空间是操作系统概念
- Swap空间解决系统物理内存不足问题
- Swap空间存在于磁盘
- Swap空间与主存发生置换
- 虚拟内存是进程概念
- 虚拟内存解决进程物理内存不足问题
- 虚拟内存存在于磁盘
- 虚拟内存与主存发生置换
5.文件管理
5.1 操作系统的文件管理
文件的逻辑结构
- 逻辑结构的文件类型
- 有结构文件
- 文本文件、 文档 、媒体文件
- 文件内容由定长记录和可变长记录组成
- 定长记录存储文件格式、文件描述等结构化数据项
- 可变长记录存储文件具体内容
- 例如:PNG文件标记–PNG数据块–文件结束标记
- 无结构文件
- exe文件、 dll链接库文件、 so文件
- 二进制文件 、链接库
- 也称为流式文件
- 文件内容长度以字节为单位
- 有结构文件
- 顺序文件
- 顺序文件是指按顺序存放在存储介质中的文件
- 磁带的存储特性使得磁带文件只能存储顺序文件
- 顺序文件是所有逻辑文件当中存储效率最高的
- 顺序文件的增删改效率低
- 索引文件
- 可变长文件不适合使用顺序文件格式存储
- 索引文件是为了解决可变长文件存储而发明的一种文件格式
- 索引文件需要配合索引表完成存储的操作
- 索引表:[键 ,逻辑地址]
- 逻辑结构的文件类型
辅存的存储空间分配
- 辅存的分配方式
- 连续分配
- 顺序读取文件内容非常容易,速度很快
- 对存储要求高,要求满足容量的连续存储空间
- 链接分配
- 链接分配可以将文件存储在离散的盘块中
需要额外的存储空间存储文件的盘块链接顺序 - 隐式链接
- 隐式分配的下一个链接指向存储在当前盘块内
- 隐式分配适合顺序访问,随机访问效率很低
- 可靠性差,任何一个链接出问题都影响整个文件
- 显式链接
- FAT( File Allocation Table) [物理块 ,下一盘块]
- 不支持高效的直接存储(FAT记录项多)
- 检索时FAT表占用较大的存储空间(需要将整个FAT加载到内存)
- 链接分配可以将文件存储在离散的盘块中
- 索引分配
- 把文件的所有盘块集中存储(索引)
- 读取某个文件时,将文件索引读取进内存即可
- 每个文件拥有一个索引块,记录所有盘块信息
- 索引分配方式支持直接访问盘块
- 文件较大时,索引分配方式具有明显优势
- 连续分配
- 辅存的分配方式
辅存的存储空间管理
空闲表
- [序号, 第一个空闲盘块号, 空闲盘块数]
- 空闲盘区的分配与内存分配类似
- 首次适应算法、循环适应算法等
- 回收过程也与内存回收类似
空闲链表
- 空闲链表法把所有空闲盘区组成一个空闲链表
- 每个链表节点存储空闲盘块和空闲的数目
位示图
- 位示图维护成本很低
- 位示图可以非常容易找到空闲盘块
- 位示图使用0/1比特位,占用空间很小
- 0:未使用,1:已使用
盘块/磁道 1 2 3 1 0 0 0 2 0 1 0 3 1 0 1
目录管理
- 目录树:
- 任何文件或目录都只有唯一路径
- 文件描述信息
- 文件标识符 文件类型 文件权限 文件物理地址 文件长度 文件连接计数 文件存取时间 索引节点编号 文件状态 访问计数 链接指针
- 目录树:
5.2 Linux文件的基本操作
Linux目录
- Linux一切皆文件
- 常用目录:/bin /etc /home /usr /opt /proc /dev /mnt /lib /var …
目录 描述 /bin 存放二进制可执行文件(ls,cat,mkdir等),常用命令一般都在这里 /etc 存放系统管理和配置文件 /home 存放所有用户文件的根目录,是用户主目录的基点,比如用户user的主目录就是/home/user /usr 用于存放系统应用程序,比较重要的目录/usr/local 本地系统管理员软件安装目录 /opt 额外安装的可选应用程序包所放置的位置 /proc 虚拟文件系统目录,是系统内存的映射。可直接访问这个目录来获取系统信息。 /root 超级用户(系统管理员)的主目录 /sbin 存放二进制可执行文件,只有root才能访问 /dev 用于存放设备文件 /mnt 系统管理员安装临时文件系统的安装点,系统提供这个目录是让用户临时挂载其他的文件系统。 /boot 存放用于系统引导时使用的各种文件 /lib 存放跟文件系统中的程序运行所需要的共享库及内核模块 /var 用于存放运行时需要改变数据的文件 - 相对路径:相对当前目录开始的目录
- 绝对路径:相对根目录开始的目录
Linux文件常用操作
- 创建:
- touch file
- vim file2 创建并编辑file2
- mkdir dir1 创建文件夹dir1
- 删除
- rm file
- rm -r dir1/ 递归删除文件夹dir1
- 读取
- cat file2
- 写入
- vim file2 创建并编辑file2
- 创建:
文件类型
- 普通文件(-)
- 目录文件(d)
- 符号链接(l)
- 设备文件(b、 c)
- 套接字(s)
- FIFO(p)
Linux的文件系统
文件系统概览
- FAT
- FAT(File Allocation Table)
- FAT16、 FAT32等,微软Dos/Windows使用的文件系统
- FAT
使用一张表保存盘块的信息
- NTFS
NTFS (New Technology File System)
- WindowsNT环境的文件系统
- NTFS对FAT进行了改进,取代了旧的文件系统
- EXT2/3/4
- EXT(Extended file system):扩展文件系统
- Linux的文件系统
- EXT2/3/4 数字表示第几代
Ext文件系统
- Boot Sector:启动扇区,安装开机管理程序
Block Group:块组,存储数据的实际位置
Boot Sector
Block Group
- SuperBlock
- 记录整个文件系统相关信息的地方
- Block和Inode的使用情况
- 时间信息、控制信息等
- Inode Bitmap
- Inode的位示图
- 记录已分配的Inode和未分配的Inode
- Block Bitmap
- 功能与Inode bitmap类似
- 记录Data block的使用情况
- Inode Table
- 存放文件Inode的地方
- 每一个文件(目录)都有一个Inode
- 是每一个文件(目录)的索引节点
- Inode:
- 文件类型 文件权限 文件物理地址 文件长度 文件连接计数 文件存取时间 索引节点编号 文件状态 访问计数 链接指针 …
- 文件名不是存放在Inode节点上的,而是存放在目录的Inode节点
- 列出目录文件的时候无需加载文件的Inode
- Data Block
- Data block是存放文件内容的地方
- 每个block都有唯一的编号
- 文件的block记录在文件的Inode上
- SuperBlock
6.设备管理
广义的IO设备
- 对CPU而言,凡是对CPU进行数据输入的都
- 对CPU而言,凡是CPU进行数据输出的都是输出设备是输入设备
广义的IIO设备分类
- 使用特性分类
- 存储设备: U盘 内存 磁盘
- 交互IO设备:键盘 显示器 鼠标
- 信息交换的单位
- 块设备 :磁盘 SD卡
- 字符设备:打印机 Shell终端
- 设备共享属性
- 独占设备
- 共享设备
- 虚拟设备
- 传输速率
- 低速设备
- 中速设备
- 高速设备
- 使用特性分类
IO设备的缓冲区
- 背景:CPU与IO设备的速率不匹配
- 减少CPU处理IO请求的频率
- 提高CPU与IO设备之间的并行性
- 专用缓冲区只适用于特定的IO进程
- 当这样的IO进程比较多时,对内存的消耗也很大
- 操作系统划出可供多个进程使用的公共缓冲区,称之为缓冲池
SPOOLing技术
- 虚拟设备技术
- 是关于慢速字符设备如何与计算机主机交换信息的一种技术
- 利用高速共享设备将低速的独享设备模拟为高速的共享设备
- 逻辑上,系统为每一个用户都分配了一台独立的高速独享设备
- SPOOLing技术把同步调用低速设备改为异步调用
- 在输入、输出之间增加了排队转储环节(输入井、输出井)
- SPOOLing负责输入(出)井与低速设备之间的调度
- 逻辑上,进程直接与高速设备交互,减少了进程的等待时间
7.实践
7.1 线程同步实践
- 互斥量
- 两个线程的指令交叉执行导致了同步问题
- 互斥量可以保证先后执行
- 原子性
- 这一系列操作要么全部执行完成,要么全部没有执行
- 原子性是指一系列操作不可被中断的特性
- 不存在部分执行部分未执行的情况
- 互斥量(互斥锁),处于两态之一的变量:解锁和加锁
- 互斥量是最简单的线程同步的方法
- 两个状态可以保证资源访问的串行
- 开发者可以直接使用API完成资源的加锁、解锁操作
- 操作系统直接提供了互斥量的API
- C 语言
- pthread_mutex_lock
- pthread_mutex_t
- pthread_mutex_unlock
- Java
- synchronized
- C 语言
- 自旋锁
- 和互斥锁有什么不一样的?
- 使用自旋锁的线程会反复检查锁变量是否可用
- 自旋锁也是一种多线程同步的变量
- 自旋锁不会让出CPU,是一种忙等待状态
- 死循环等待锁被释放
- 操作系统内部很多地方使用的是自旋锁
- 自旋锁避免了进程或线程上下文切换的开销
- 自旋锁不适合在单核CPU使用,因为自旋锁不会让出CPU
- api
- pthread_spinlock_t
- pthread_ spinlock lock
- pthread_ spinlock _unlock
- 读写锁
- 读取的时候并不会改变临界资源的值
- 临界资源多读少写
- 是否存在效率更高的同步方法?
- 允许多个读者同时访问资源以提高读性能
- 读写锁是一种特殊的自旋锁
- 对于写操作则是互斥的
- API
- pthread_rwlock_t
- pthread_rwlock_rdlock(读锁)
- pthread_rwlock_wrlock(写锁)
- 互斥量、自旋锁、读写锁 同步过程:等待解锁–加锁–【临界资源】–解锁
- 条件变量
- 条件变量允许线程睡眠,直到满足某种条件
- 条件变量是一种相对复杂的线程同步方法
- 当满足条件时,可以向该线程信号,通知唤醒
- 生产者消费者问题
- 缓冲区满时,不允许生产者往缓冲区生产,生产者必须等待
- 缓冲区小于等于0时,不允许消费者消费,消费者必须等待
- 当生产者生产一个产品时,唤醒可能等待的消费者
- 当消费者消费一个产品时,唤醒可能等待的生产者
- API
- pthread_cond_t,配合互斥量使用
- pthread_cond_wait(等待条件满足)
- pthread_cond_signal(等待被唤醒)
- 条件变量同步流程:等待解锁–加锁保护条件变量–等待条件满足被唤醒–【临界资源】–解锁
同步方法 | 描述 |
---|---|
互斥锁 | 最简单的一种线程同步方法,会阻塞线程 |
自旋锁 | 避免切换的一种线程同步方法,属于“忙等待”,不让出CPU |
读写锁 | 为“读多写少” 的资源设计的线程同步方法,可以显著提高性能 |
条件变量 | 相对复杂的一种线程同步方法,有更灵活的使用场景 |
7.2 进程同步实践
使用fork系统调用创建进程
- fork创建的进程初始化状态与父进程一样
- fork系统调用是用于创建进程的
- 系统会为fork的进程分配新的资源
- fork会返回两次,分别返回子进程id和0
- fork系统调用无参数
- 返回子进程id的是父进程,返回0的是子进程
共享内存
- 进程的线程共享进程资源
- 进程共享计算机资源
- 在某种程度上,多进程是共同使用物理内存的
- 由于操作系统的进程管理,进程间的内存空间是独立的
- 进程默认是不能访问进程空间之外的内存空间的
- 共享存储允许不相关的进程访问同一片物理内存
- 共享内存是两个进程之间共享和传递数据最快的方式
- 共享内存未提供同步机制,需要借助其他机制管理访问,比如通过一个Boolean的变量来控制是否可读可写
- 共享内存是高性能后台开发中最常用的进程同步方式
- 共享内存 使用流程
- 申请共享内存
- 连接到进程空间
- 脱离进程空间
- 使用共享内存&删除
- 代码实现
Unix域套接字
- 域套接字是一种高级的进程间通信的方法
- Unix域套接字可以用于同一机器进程间通信
- 套接字(socket)原是网络通信中使用的术语
- Unix系统提供的域套接字提供了网络套接字类似的功能
- Nginx、uWSGI
- 服务端
- 创建套接字
- 绑定(bind)套接字
- 监听(listen)套接字
- 接收&处理信息
- 客户端
- 创建套接字
- 连接套接字
- 发送信息
- 代码实现
- 提供了单机简单可靠的进程通信同步服务
- 只能在单机使用,不能跨机器使用
8.关于我
一个专注基础知识的十二线小码农,本着 基础,体系,实践,分享 的学习理念,在自我提升的同时分享自己的心得体会,不断完善,周而复始。
BaseDev系列只整理点到为止的知识纲领,不求甚解;欲知其所以然者还得回归书本且付诸实践