操作系统(学习笔记)
操作系统(学习笔记)
术语
PCB=process control block=进程控制块,用于存储进程相关信息,以便进程切换;
GDT=global descriptor table=全局描述符表,用于存储系统进程描述信息和LDT信息;
LDT=local descriptor table=局部描述符表,用于存储用户进程描述信息;
GDTR=global descriptor table register=全局描述符表寄存器,用于存储全局描述符表在内存中的地址;
LDTR=local descriptor table register=局部描述符表,用于存储局部描述符表在内存中的地址;
TLB=Translation Look-aside Buffer=地址变换高速缓存=快表,实质上它是一种cache;
MMU=Memory Management Unit的=内存管理单元,有时称作分页内存管理单元;
DPL=descriptor privilege level=门或段特权级
CPL=current privilege level=当前程序的特权级
RPL=request privilege level=进程对段访问的请求权限
semaphore英 /ˈseməfɔː(r)/ 美 /ˈseməfɔːr/n. 信号量、信号标、信号对象
mutex 英[m'juːteks]美[m'juːteks] n. 互斥;互斥元,互斥体;互斥量
信号量计数:可用资源的数量;
wait()使用资源,减少信号量计数
signal()释放资源,增加信号量计数
信号量计数为0,所有资源都被使用,可用资源为0;
block()阻塞、挂起进程
wakeup()唤醒、重新启动进程
FIFO队列 FIFO(First Input First Output)队列,即先入先出队列
外部碎片和内部碎片
区别 |
外部碎片(未分配) |
内部碎片(已分配) |
性质不同 |
是还没有被分配出去(不属于任何进程),但由于太小了无法分配给申请内存空间的新进程的内存空闲区域 |
是已经被分配出去(能明确指出属于哪个进程)却不能被利用的内存空间 |
存储块不同 |
是出于任何已分配区域或页面外部的空闲存储块 |
是处于区域内部或页面内部的存储块 |
状态不同 |
这些存储块的总和可以满足当前申请的长度要求,但是由于它们的地址不连续或其他原因,使得系统无法满足当前申请 |
占有这些区域或页面的进程并不使用这个存储块。而在进程占有这块存储块时,系统无法利用它。直到进程释放它,或进程结束时,系统才有可能利用这个存储块 |
内存管理
重定位 |
让内存用起来:将程序放到内存中,让程序跑起来,PC指向开始地址,内存就用起来了; 地址重定位:编译时重定位(效率更高)、载入时重定位(灵活性好); 编译时重定位:程序只能放在内存固定位置; 载入时重定位:程序一旦载入,内存就不能动了; 重定位:可变的基准地址+不变的偏移地址; 程序载入后也要移动; 运行时重定位:程序换入时,进行重定位; 程序换入时,将新的基地址写入PCB,以便完成重定位; 程序不是常驻内存,而是将执行的程序换入内存,而将不执行的程序换出内存; PCB的基址放入基址寄存器,和程序中的偏移地址相加计算重定位地址,然后再翻译成物理地址; PCB→基址寄存器→偏移地址→重定位→物理地址; |
|||||||||||||||||||||||||||||||||||||
分段 |
内存分段管理:每个段有各自的特点、用途; 代码段、数据段、堆栈段; 分段管理符合用户观点:可以独立考虑每个段(分治) 如何定位具体指令(数据)<断号,段内偏移>mov [es:bx],ax 操作系统也是一个进程,操作系统的描述符表,称为GDT=globle descriptor table; 每一个用户程序也是一个进程,也有各自的描述符表(段表),称为LDT=local descriptor table
内存分段(一个进程)
栈、堆辨析: 1、栈区(stack):由编译器自动分配释放 ,存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈。 2、堆区(heap):由程序员分配释放, 若程序员不释放,程序结束时可能由操作系统回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
GDT+LDT+偏移;
|
|||||||||||||||||||||||||||||||||||||
分页 |
内存如何分割:固定分区(等分)、可变分区(不等分); 以分配分区表,空闲分区表;需要多少,就割多少; 内存分配:首先适配(随机)最佳分配(挑最小的分配,产生细小空间),最差分配(挑最大的分配,分配比较均匀); 分页:解决内存分区导致的内存效率问题; 可变分区造成的问题:产生内存碎片; 解决:将空闲分区合并,需要移动一个段(复制内存)内存紧缩; 内存紧缩需要花费大量时间,不可取; 不产生面包碎屑;将面包切成片,将内存分成页; 将每个段内存请求,系统一页一页的分配给这个段; 内存需要分页,程序需要分段;最多浪费一页4k; 通过页表到内存中找;MMU内存管理单元,通过逻辑地址,寻找内存物理地址; 每个段都打散成很多段,相应的,内存也分割成很多页;
多级页表 为了提高内存空间利用率,页应该小,但是页小了,分的页就多了,页表就大了; 页表的作用:逻辑页(页号)→物理页(页框号) 页面尺寸通常4K,地址32位4G内存,有2^20个页面; 2^20个页表项都要存放在内存中,需要4M内存,系统并发10个进程,就需要40M内存; 实际上,很多逻辑地址根本不会用到; 将不使用的地址项从页表中删除,减小页表大小,减少内存浪费; 页表必须连续,否则要挨个查找,访问一次内存就要提前访问内存很多次,大大降低效率; 页表连续时,用页表起始页加上一个偏移量,就可以一次性查找到页表项; 既要连续,又要占用内存少;就要使用分级页表; 页目录+页表;每个页目录项对应1K个页表,需要4M内存; 多级页表,空间利用率好(节省内存),但需要增加访问次数,降低访问效率; 每增加一级,访问内存次数就要增加一次,但是内存占用会大大减少; TLB快表,是一组相连快速存储,是一个寄存器; 记录正在使用的多个页表,再次访问时,可以一次直达对应地址; 快表相当于记住最近搜索项,或最近查找项; 快表+多级页表:节省内存、又很快; TLB命中率有多少?要想TLB好使,命中率必须达到一定水平; 要想真正实现“近似访存1次”TLB命中应该很高; TLB越大越好,但是TLB寄存器很贵,通常只有[64-1024]; 程序地址访问存在局部性locality in space,就是说经常集中性访问一段内存; TLB解决多级页表访问效率低的问题;
|
|||||||||||||||||||||||||||||||||||||
虚拟内存 |
程序分段(打散)→页表(虚拟内存)→物理地址; 虚拟内存实现了既支持分段又支持分页的内存视图; 段、页同时存在:段面向用户,页面向硬件; 虚拟内存将段和页紧密的结合在一起; 段号+偏移(CS:IP)→段表→段号+偏移→虚拟地址→页号+偏移→页表→物理页号+偏移
|
进程=正在进行的程序=执行中的程序
进程 |
程序的本质:数据和对数据的处理; 进程的本质:正在运行(执行/动态)的程序; 进程是操作系统进行资源化分配和调度的基本单位; 进程是应用程序关于某些数据集合上的一次运行活动; 进程是程序的一次执行过程; 进程是动态的,程序是动态的,执行的程序才是进程,没有执行的程序不是进程; 动态的程序才是进程,静态的程序不是进程; 每个进程拥有独立的地址空间; 进程之间的地址空间是隔离的; 一个进程崩溃不会影响另一个进程;一个进程崩溃不会影响操作系统; 地址空间包括代码段、数据段、堆栈段; 代码段:存储程序的代码; 数据段:存储程序的全局变量和动态分配的内存; 堆栈段:存储函数运行时的局部变量;
|
多进程 |
CPU计算速度和IO速度严重不匹配;5.7*10^5:1 导致CPU利用率很低; 多道程序,交替执行,可以大大提高CPU利用率; 一个CPU上交替执行多个程序:并发(同时出发,交替执行); 核心是如何在不同任务间进行切换; 而切换的核心就是中断技术; 切出去的时候要记录当前程序的执行状态,切回来的时候再读出当时的状态,以便接续执行; 进程:进行(执行)中的程序; 运行的程序和静态程序不一样。 需要描述这些不一样,都记录在PCB中; PCB:process ctrl block(进程控制块),用来记录当前进程的当前状态; 在操作系统代码当中是一个结构体:struct task_struct{...} Ø 进程有开始有结束,程序没有; Ø 进程会走走停停,走停对程序没有意义; Ø 进程需要记录ax、bx,程序不用; 多进程:多个程序交替执行,分别成为进行中的程序; 如何实现多进程图像: 1. 通过映射表实现内存的分离; 2. 读写PCB,OS中最重要的结构,贯穿始终; 3. 要操作寄存器完成切换; 4. 要写调度程序; 5. 要有进程同步和合作; 6. 要有地址映射(防止相互干扰);
进程=资源+指令执行序列; 线程:保留了并发的优点,避免了进程切换代价; 将资源和指令切换分开; 一个资源+多个指令执行序列; 线程:只切换指令,而不切换资源; 指令的切换的核心是Yield; Create就是第一次切换时的样子; 用户级线程、内核级线程;
|
进程同步 |
同步:多个进程的推进合理有序; 进程之间的合作,合理有序的推荐,而不是任意向前推荐; 一个进程发出信号,另一个进程等到该信号,才能继续向下执行; 关键词:信号、合作、同步、等待、阻塞; 需要让进程走走停停,来保证多进程之间的合理有序; 分析走和停的实际,是多进程同步的关键; n 同步并不是同时,而是交替执行; n 交替执行不是随意的交替,而是合理的有序的交替; 程序可以有多个(多道),但是正在执行的程序只能有一个;
|
信号量 |
仅仅依靠一个counter信号,不足以支持进程的sleep和wakeup; 需要一个信息更加丰富的量,来记录信号; 通过信号量sem实现等待sleep与唤醒wakeup; sem小于0,表示有进程在等待资源,生产者处于睡眠状态,唤醒; 信号量:1965年,由荷兰学者Dijkstra提出的一种特殊整形变量,用来sleep和wakeup; semphore英 /ˈseməfɔː(r)/ 美 /ˈseməfɔːr/n. 信号标,信号量信号标信号对象 保护信号量: 竞争条件:race condition:和调度有关的共享数据语义错误; 错误由多个进程并发操作共享数据引起; 原子操作:一段代码只允许一个进程进入;
临界区:一次只允许一个进程进入的该进程的那一段代码; 找出临界区代码; 原子操作、互斥; 临界区代码保护原则: ①基本原则:互斥进入,如果一个进程在临界区中执行,其他进程不允许进入; 这些进程间的约束关系称为互斥 mutual exclusion;这保证了临界区; 好的临界区保护原则: ②有空让进:若干进程要求进入空闲临界区时,应尽快使一些进程进入临界区; ③有限等待:从进程发出进入请求到允许进入,不能无限等待; 解决竞争调价你的方法 值日算法(轮换算法)、买牛奶留标签算法(标签算法)、面包店算法(取号算法); 面包店算法的正确性: n 互斥进入:Pi在临界区内,Pk试图进入,一定有(num[i],i)<(num[k],k),Pk循环等待; n 有空进入:如果没有进程在临界区中,最小序号的进程一定能够进入; n 有限等待:离开进阶区的进程再次进入一定排在最后(FIFO),所以任一个想进入进程至多等待n个进程; 软硬件协同设计; 关闭中断法:关闭中断cli=close interrupt,执行完临界区代码再开中断sti=start interrupt; 关闭中断,对于多CPU不好使; 硬件原子指令法:给一段指令上锁,锁的本质就是一个变量(整形变量),将变量赋值为某一个值,就锁住,执行完再赋值为另一个值,就解锁了; 原子指令,一条指令是原子的,要么被执行,要么没有执行,不可分割; 临界区指令:不能被中途打断的指令, |
CPU调度 |
多个进程,应该选择哪个执行,这就是调度; 调度思想: ①按照先后顺序进行调度: 先来后到,谁先来,先执行谁; ②按照优先级进行调度: 任务短的可以适当优先; 调度目标:如何让进程满意,时间是关键,也就是快 n 尽快结束任务,周转时间短(从任务进入到任务结束) n 用户操作尽快反应:响应时间短(从操作发生到响应) n 系统内耗时间少:吞吐量(完成任务量) 如何做到合理?折中、综合考虑 n 吞吐量和响应时间之间有矛盾; n 响应时间小→切换次数多→系统内耗大→吞吐量小; n 前台任务和后台任务的关注点不同; n 前台任务关注相应时间,后台任务关注周转时间; n IO约束型任务和CPU约束型任务各有特点; n IO优先级更高一些,更利于并行; 折中和综合让系统变得复杂,然而系统又要尽量简单;
调度算法 FCFS=First Come,First Served,先来先服务;体现公平; SJF=short job first,短作业优先;周转时间最小; RR=round Robin按时间片轮转调度; 时间片大:响应时间太长;时间片小,吞吐量小;折中:时间片10-100ms切换时间0.1-1ms(1%); 定义前台任务和后台任务两队列,前台RR,后台SJF,没有前台任务时才调度后台任务; 后台任务优先级动态升高,防止饥饿;执行一段时间后,必须再调低,防止前台任务响应迟钝;
调度函数schedule()
|
fork |
fork英 /fɔːk/ 美 /fɔːrk/ n. 餐叉,叉子;耙,叉;岔路,支流;叉状部件,叉状物; v. (道路、河流等)分岔,岔开;(用餐叉)叉起;耙地,叉掘;走岔路中的一条;
fork进程控制函数,叉子函数、分叉函数;形象的表示进程之间的切换; 作用: 创建新进程;函数原型: pid_t fork(void);需要包含头文件 <unistd.h> 返回值:成功,两次返回(子进程返回 0,父进程返回子进程 ID);若出错,返回 -1 pid_t getpid(void);获取当前进程id;get process id pid_t getppid(void);获取当前进程的父进程id;get parent process id fork 的一个特性是父进程所有打开的文件描述符都被复制到子进程中。 父进程和子进程每个相同的打开描述符共享一个文件表项; 父进程和子进程共享同一个文件偏移量; 在 fork 之后处理文件描述符有以下两种常见的情况。 (1) 父进程等待子进程完成,在这种情况下,父进程无需对其描述符做任何处理。当子进程终止后,它曾进行过读、写操作的任一共享描述符的偏移量已做了相应更新。 (2) 父进程和子进程各自执行不同的程序段,在这种情况下,在 fork 之后,父进程和子进程各自关闭他们不需使用的文件描述符,这样就不会干扰对方使用的文件描述符。 ———————————————— fork 失败的两个主要原因是: (1) 系统中已经有太多的进程 (2) 该实际用户 ID 的进程总数超过了系统限制,CHILD_MAX 规定了每个实际用户 ID 在任一时刻可拥有的最大进程数。 fork 的用法 (1) 一个父进程希望复制自己,使父进程和子进程同时执行不同的代码段。 (2) 一个进程要执行不同的程序,在这种情况下,子进程从 fork 返回之后立即调用 exec 系列
|
操作系统
操作系统概述
|
BIOS是英文"Basic Input Output System"的缩略词,就是"基本输入输出系统"。 BIOS是个人电脑启动时加载的第一个软件。 操作系统是计算机硬件和应用之间的一层软件; 操作系统是管理硬件的软件; 方便我们使用硬件,如显存; 高效使用硬件,如开多个端口; 没有操作系统的计算机叫做裸机;因此操作系统相当于计算机的衣服;
CPU管理、内存管理、终端管理、磁盘管理、文件管理、网络管理、电源管理、多核管理; 操作系统
|
|||||||||||||||||
启动过程 |
1. 刚开机时CPU处于实模式 2. 开机时,CS=0xFFFF,IP=0x0000 3. 寻址0xFFFF0(ROMBIOS映射区) 4. 检查RAM、键盘、显示器、磁盘 5. 将磁盘0磁道0扇区读入0x7c00处 6. 设置cs=0x7c00,ip=0x0000
|
|||||||||||||||||
操作系统接口 |
POSIX:Portable Operating System Interface of Unix(IEEE制定的一个标准族) 接口表现为函数调用,又由系统系统,所以称为系统调用;
|
|||||||||||||||||
系统调用 |
主动进入内核的方法:中断指令int(interrupt)int 0x80 n int指令将使CS红的CPL改成0,以进入内核 n 这是用户程序发起的调用内核代码的唯一方式; 系统调用的核心 ① 用户程序红包含一段包含int指令的代码 ② 操作系统写中断处理,获取想要调用程序的编号; ③ 操作系统根据编号执行相应代码
将内核程序和用户程序隔离 区分内核态和用户态由于CS:IP是当前指令,所以用CS最低两位来表示:0是内核态,3是用户态; 内核态可以访问任何数据,用户态不能访问内核数据;对于指令跳转也一样,实现了隔离; n 获取特权级:访问的数据段DS的最低两位,CPL(CS)RPL(RS)DPL (privilege level) n 特权级判定:如果DPL>=CPL DPL>=RPL才能访问;
|
|||||||||||||||||
操作系统历史 |
①IBMSYS(1955-1965) 监控系统:实现任务批处理 ②OS/360:(1965-1980) 360表示全方位服务,开发周期5000人年 需要让一台计算机干多种事 多道程序multiprogramming 作业之间的切换和调度称为核心,既有IO任务又有计算任务,需要让计算机CPU忙碌 ③MULTICS多人使用(1965-1980) 每个人启动一个作业,作业之间快速切换 分时系统timesharing 代表:MIT MULTICS(MULTIplexed Information and Computer Service) 核心仍然是任务切换,但是资源复用思想对操作系统影响很大,虚拟内存就是一种复用; ④Unix(1980-1990) Unix是一个简化的MULTICS ⑤Linux(1990-2000) 多进程结构是计算机的基本图谱; ⑥DOS:CPM QDOS MSDOS Basic解释器 FAT管理磁盘 ⑦Windows 可视化 n 多进程图谱ProcessView(CPU、内存); n 文件操作视图FileView(IO、磁盘); |
特权级=PL=Privilege Level
描述符特权级(DPL,Descriptor Privilege Level)
|
实施特权级保护的第一步,是为所有可管理的对象赋予一个特权级,以决定谁能访问它们。每个 Descriptor 都具有描述符特权级(DPL,Descriptor Privilege Level)字段,Descriptor 总是指向它所“描述”的目标对象,代表着该对象,因此该字段(DPL)实际上是目标对象的特权级。
|
当前特权级(CPL,Current Privilege Level)
|
当处理器正在一个代码段中取指令和执行指令时,那个代码段的特权级叫做当前特权级(Current Privilege Level, CPL)。 正在执行的这个代码段,其选择子位于段寄存器CS中,其最低两位就是当前特权级的数值。 |
请求特权级(RPL,Request Privilege Level)
|
RPL也就是指请求者的特权级别(Requestor’s Privilege Level)。 |
特权指令(PI,Privileged Instructions)
|
不同特权级别的程序,所担负的职责以及在系统中扮演的角色是不一样的。计算机系统的脆弱性在于一条指令就能改变它的整体运行状态,比如停机指令hlt 和对控制寄存器CRO的写操作,像这样的指令只能由最高特权级别的程序来做。因此,那些只有在当前特权级 CPL 为 0 时才能执行的指令,称为特权指令(Privileged Instructions)。 |
输出特权级(IOPL,I/O Privilege Level)
|
在处理器的标志寄存器EFLAGS中,位13、位12是IOPL位,也就是输入/输出特权级(I/O Privilege Level),它代表着当前任务的I/O特权级别。某些指令,例如IN,OUT,CLI需要 I/O 特权,这些操作根据 IOPL 和 CPL 确定合法性。 |
内存分段的意义
- 在多任务环境下,系统中有多个程序在运行;
- 程序之间需要隔离!
- 分段是存储管理的一种方式,为保护提供基础;
- 不同程序在不同段中;
- 一个程序可以包含多个段;
- 段用于封闭具有共同属性的存储区域;
,,