操作系统基础部分
1.进程与线程的区别
· 进程是系统进行资源分配和管理的基本单位;线程是进程的执行单元,是进程内调度的实体,CPU调度和分派的基本单位。
· 进程有自己独立的地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、数据等,这种操作非常昂贵。
而线程是共享进程中的数据的,使用相同的地址空间。因此,CPU切换一个线程的花费比进程小,创建线程的开销也比进程小。
· 线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据。
· 多进程程序更健壮,进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其他进程产生影响;而线程出现问题,可能导致整个程序的奔溃。
应用场景举例:
QQ 和浏览器是两个进程,浏览器进程里面有很多线程,例如 HTTP 请求线程、事件响应线程、渲染线程等等.
线程的并发执行使得在浏览器中点击一个新链接从而发起 HTTP 请求时,浏览器还可以响应用户的其它事件。
2.进程状态
如上图,进程有以上五大状态。而发生进程转换的原因:
· 空 --> 新建态:创建执行程序的新进程,可能的情况有:新的批处理作业。
· 新建 --> 就绪:操作系统准备好接纳一个程序时,就会由新建态转入就绪态
· 就绪 --> 运行:操作系统的调度器选择某个进程执行
· 运行 --> 退出:导致进程终止的原因有:
- 正常完成
- 异常情况(超时、系统无法满足进程所需的内存空间,越界、算术错误、父进程终止等)
· 运行 --> 就绪:- 时间片到达,调度器分派其他进程执行
- 更高优先就的进程抢占该进程
· 运行 --> 阻塞:进程请求它必需等待的事件,比如I/O操作,只有在获得等待的资源后才能继续执行。
· 阻塞 --> 就绪:进程等待的事件发生
应该注意以下内容:
补充xv6中的PCB
3.进程的调度算法
上图展示了调度过程。长程调度是指进程创建时候,待操作系统允许容纳后由进入就绪队列。 短程调度是CPU调度,在就绪队列中选择一个进程,并分配处理器资源。
中程调度是指从suspend-queue移动到就绪队列的过程。
下图是对各个调度算法的比较,简单总结一下:
- FCFS,按照先来先服务原则。缺点:对长进程偏好,系统平均周转时间会很长
- Round Robin,抢占式。缺点:如果时间片设置地太短,系统整体效率也会很低(频繁地进程切换)
- SPN,非抢占式。从就绪队列中选择时间最短的进程执行。缺点:1)可能发生饿死,2)需要估计每个进程的执行时间
- SRT,抢占式,每一次新进程到来,比较新进程和当前正在执行进程的剩余执行时间。它的缺点同上。
- HRRN,高响应比优先。非抢占式,有效地解决了饿死问题。
- 多级反馈队列。
i) 设置多个就绪队列并为每个队列设置不同的优先级,第一个队列优先级最高,其余依次递减。
ii) 优先级越高的队列分配的时间片越短,进程到达之后按FCFS放入第一个队列,如果调度执行后没有完成,那么放到第二个队列尾部等待调度.
只有当前一个队列为空的时候才会去调度下一个队列的进程。
另外,根据它们相应的应用场景进行说明:
批处理系统 没有太多用户操作,目的是保证吞吐量和周转时间,FCFS,SPN,SRT
交互式系统,有大量用户响应,目标是进行快速响应。RR和Feedback
4.进程同步问题
1)哲学家就餐问题
问题描述:五个哲学家围着一张圆桌,每个哲学家面前放着食物。哲学家的生活有两种交替活动:吃饭以及思考。
当一个哲学家吃饭时,需要先拿起自己左右两边的两根筷子,并且一次只能拿起一根筷子。
解决方法:i)每次只允许4位哲学家就餐
ii)区分奇偶次序,奇数的哲学家先拿左边筷子,再拿右边筷子,偶数的相反。
2) 读者写者问题
- 读者享有优先级
信号量x用于对readcount(读者数量)进行互斥,信号量wsem用于对写操作互斥。当第一次进行读的时候,要wait(wsem),最后一个读者退出的时候,signal(wsem)
3) 生产者消费者模型
i)无限缓冲区的情况。
其中,信号量s是对缓冲区进行互斥操作(append/take),信号量n是保证商品数量互斥。
ii)有限缓冲区的情况。
- 引入信号量empty,初始值为缓冲区大小
- 每次生产的过程,要先wait(empty). 每次消费的过程后,要signal(empty)
5.进程通信方法
1)管道
通过pipe函数创建,fd[0]用于读,fd[1]用于写。限制:i)只支持半双工,ii) 只能在父子进程/兄弟进程中使用。
2)FIFO 命名管道
去除了管道使用范围上的限制。常用于客户-服务器间传递数据。
3)消息队列
相比于 FIFO,消息队列具有以下优点:
4)信号量
它是一个计数器,用于为多个进程提供对共享数据对象的访问。
5)共享存储
允许多个进程共享一个给定的存储区。需要使用信号量用来同步对共享存储的访问。
6.死锁
1)死锁产生的条件
2)死锁处理
i) 预防死锁:破坏产生死锁的4个必要条件中的一个或者多个;实现起来比较简单,但是如果限制过于严格会降低系统资源利用率以及吞吐量
ii) 避免死锁:在资源的动态分配中,防止系统进入不安全状态(可能产生死锁的状态)-如银行家算法
iii) 检测死锁:允许系统运行过程中产生死锁,在死锁发生之后,采用一定的算法进行检测,并确定与死锁相关的资源和进程,采取相关方法清除检测到的死锁。实现难度大
iv) 解除死锁:与死锁检测配合,将系统从死锁中解脱出来(撤销进程或者剥夺资源)。对检测到的和死锁相关的进程以及资源,通过撤销或者挂起的方式,
释放一些资源并将其分配给处于阻塞状态的进程,使其转变为就绪态。实现难度大
7.虚拟内存的作用,分页系统
虚拟内存的目的:让物理内存扩充成更大的逻辑内存,从而让程序获得更多的可用内存。
内存管理单元(MMU)管理着地址空间和物理内存的转换,其中的页表(Page table)存储着页(程序地址空间)和页框(物理内存空间)的映射表。
一个虚拟地址分成两个部分,一部分存储页面号,一部分存储偏移量。
8.页面置换算法
1)概述:
在程序运行过程中,如果要访问的页面不在内存中,就发生缺页中断从而将该页调入内存中。此时如果内存已无空闲空间,系统必须从内存中调出一个页面到磁盘对换区中来腾出空间。
页面置换算法和缓存淘汰策略类似,可以将内存看成磁盘的缓存。在缓存系统中,缓存的大小有限,当有新的缓存到达时,需要淘汰一部分已经存在的缓存,这样才有空间存放新的缓存数据。
页面置换算法的主要目标是使页面置换频率最低(也可以说缺页率最低)。
2)几种方法
i) 最佳 - 理论算法,难以实现
所选择的被换出的页面将是最长时间内不再被访问,通常可以保证获得最低的缺页率。
ii)LRU 最近最久未使用
为了实现 LRU,需要在内存中维护一个所有页面的链表。当一个页面被访问时,将这个页面移到链表表头。这样就能保证链表表尾的页面是最近最久未访问的。
因为每次访问都需要更新链表,因此这种方式实现的 LRU 代价很高。
iii)最近未使用
iv)先进先出
选择换出的页面是最先进入的页面。该算法会将那些经常被访问的页面也被换出,从而使缺页率升高。
v ) 第二次机会算法
当页面被访问 (读或写) 时设置该页面的 R 位为 1。需要替换的时候,检查最老页面的 R 位。如果 R 位是 0,那么这个页面既老又没有被使用,可以立刻置换掉;
如果是 1,就将 R 位清 0,并把该页面放到链表的尾端,修改它的装入时间使它就像刚装入的一样,然后继续从链表的头部开始搜索。
9.分段和分页的比较
对程序员的透明性:分页透明,但是分段需要程序员显式划分每个段。
地址空间的维度:分页是一维地址空间,分段是二维的。
大小是否可以改变:页的大小不可变,段的大小可以动态改变。
出现的原因:分页主要用于实现虚拟内存,从而获得更大的地址空间;分段主要是为了使程序和数据可以被划分为逻辑上独立的地址空间并且有助于共享和保护。
10.比较静态链接和动态链接
静态链接器以一组可重定位目标文件为输入,生成一个完全链接的可执行目标文件作为输出。链接器主要完成以下两个任务:
静态库有以下两个问题:
共享库是为了解决静态库的这两个问题而设计的,在 Linux 系统中通常用 .so 后缀来表示,Windows 系统上它们被称为 DLL。它具有以下特点:
原文:https://www.cnblogs.com/xxwu1999/p/12493912.html