计算机操作系统精髓与设计原理

计算机操作系统精髓与设计原理

高速缓存:
主要解决处理器和内存的速度不匹配的问题。处理器的速度一致快于存储器的访问速度,这需要在速度、价格和大小方面进行折中。高速缓存区试图使访问速度接近现有的最快的存储器,同时保持价格便宜的大存储容量(以较为便宜的半导体存储器技术实现)。
对于高速缓存的设计可以分为:高速缓存的大小、块大小、映射函数、替换算法、写策略。
在这里插入图片描述

块大小即为高速缓存与内存交换数据的单位。当一个新块被读取到高速缓存中时,要根据映射函数确定这个块占据那个高速缓存单元,尽可能的减小替换的块在不久的将来还会被用到的可能性。这需要设计出增大命中率的替换算法,比如最近最少使用算法(LRU,Least-Recently-Used)。对于被替换的块内容需要被写回内存,写策略规定了何时发生写操作。

进程管理

背景

现代操作系统最基础的任务就是进程管理。操作系统必须为进程分配资源,使进程间可以交换信息,保护各个进程的资源不被其他进程占用,使进程可以同步。为例达到这些要求,操作系统必须为每一个进程维护一个数据结构,这个数据结构描述进程的状态和资源所有权,这样才能使操作系统进行进程控制。
在单处理器多道程序的系统中,多个进程的执行可以在同一时间交叉进行。在多处理器系统中,不仅多个进程可以交叉执行,而且可以同步执行。交叉执行和同步执行都属于并发执行。
线程概念的引入,也给当代操作系统中的进程管理带来困难。在一个多线程的系统中,进程保留这资源所有权的属性,而多个并发执行流是执行在进程中的线程。

进程概念

可以把进程当成由一组元素组成的实体,进程的两个基本元素是程序代码和代码相关的数据集。假设处理器开始执行这个程序代码,且我们把这个执行的实体叫做进程。在进程执行时,任意给定一个时间,进程都可以唯一的表征以下几个元素:标识符、状态、优先级、程序计数器、内存指针、上下文数据、IO状态信息、记账信息。这叫做进程控制块。通过进程控制块来进行进程的创建和管理。

进程的状态

操作系统的基本职责是控制进程的执行,包括确定交替执行的方式和给进程分配资源。

进程创建

通常有四个事件会创建进程:在批处理环境中,响应作业提交时会创建进程;在交互环境中,当一个新用户试图登录时会创建进程;进程派生;操作系统因为提供一项服务而创建。当操作系统为另一个进程显示请求创建一个进程时,这个动作称为进程派生。例如打开一个文件创建一个打印机服务来对这个文件进行打印。文件进程被称为父进程,打印机服务被称为子进程。

进程终止

批处理作业中包含一个Halt指令或者用于操作系统显示服务调用来终止。前一种情况,Halt指令会产生一个中断,警告系统的一个进程已经完成。此外很多错误和故障会导致一个服务请求终止。
导致终止的原因举例:正常完成,超过时限,无可用内存,越界,保护错误,算数错误,IO失效,无效指令,特权指令,数据误用,操作员或者操作系统干涉,父进程终止,父请求终止。

五态模型

五种状态

运行态:运行状态,一个处理器最多只有一个进程能处于这个状态。
就绪态:进程做好了准备,只要有机会就会执行。
阻塞/等待态:进程在某些事情发生之前不能执行,如I/O操作完成。
新建态:刚刚创建的进程,操作系统还没有把它加入到可执行进程组中。通常是进程控制块已经创建但还没有加载到内存的进程。
退出态:终止进程。

转化

空–》新建:创建一个新进程。
新建–》就绪:操作系统准备接纳一个进程时,把一个进程从新建态到就绪态。
就绪–》运行:需要一个新进程时,操作系统选择一个处于就绪态的进程,这是调度器或者分派器的工作。
运行–》退出:工作完成或者出现问题。
运行–》就绪:正在运行的进程到了“允许不被中断执行的最大时间段”。或者进程自动放弃对处理器的控制。
运行–》阻塞:正在运行的进程需要调度操作系统中一部分代码所发生的的过程。例如当运行的进程需要达到某种条件才能继续进行就会进入阻塞状态,等待条件的达成。
阻塞–》就绪:当被堵塞的进程所等待的事件达成时。
就绪–》退出:当父进程退出时,与之相关的子进程会退出。

线程

是什么

多线程是指操作系统在单个内核内支持多个并发执行路径的能力。每个进程中只有一个线程在执行的传统方法被成为单线程执行方法。
在一个进程中,可能有一个或多个线程,每个线程有:
线程的执行状态。
在未执行时保存的线程上下文。
一个执行栈。
用于每个线程局部变量的静态存储空间。
与进程内的其它线程共享的对进程的内存和资源的访问。

线程状态

派生:典型情况下,当派生一个新进程时,同时也为该进程派生了一个线程。新线程拥有自己的寄存器上下文和栈空间,且被放置在就绪队列中。
阻塞:当线程需要等待一个事件时,它将被阻塞(保护它的用户寄存器、程序计数器、栈指针),此时处理器转而执行另一个同一线程或不同进程中的就绪线程。
解除阻塞:当阻塞一个线程事件发生时,改线程被转移到就绪队列中。
结束:当一个线程完成时,其寄存器上下文和栈都会被释放。

线程同步

背景

解决多线程环境中一个线程的阻塞会导致整个进程堵塞的问题。

线程分类

用户级与内核级线程

并发

相关术语

原子操作:一个和多个指令的序列,对外是不可分的;即没有其他进程可以看到其中间状态或者中断此操作。
临界区:是一段代码,在这段代码中进程将访问共享资源,当另外一个进程已经在这段代码中运行时,这个进程就不能在这段代码中执行。
死锁:两个或两个以上的进程因其中的每个进程都在等待其他进程昨晚某些事情而不能继续执行。
活锁:两个或两个以上的进程为了响应其他进程中的变化而持续改变自己的状态但不做有用的工作。
互斥:当一个进程在临界区访问共享资源时,其他进程不能进入改临界区访问任何共享资源。
竞争条件:多个线程或者进程在读写一个共享数据时,结果依赖于它们执行的相对时间,这种情形叫做竞争。
饥饿:是指一个可运行的进程尽管能继续执行,但被调度无限期的忽视,而不能被调度执行的情况。

关注的问题

操作系统需要记住每个活跃的进程
操作系统必须为每个活跃进程分配和释放各种资源,有时,多个进程都想访问相同的资源,包括:处理器时间、存储器、文件、IO设备。
操作系统必须保护每个进程的数据物理资源,避免其他进程的无意干涉,这涉及与存储器、文件和IO设备相关的技术。
一个进程的功能和输出结果必须与执行速度无关。

信号量

常用的并发机制

信号量:用于进程间传递信号的一个整数值。在信号量上有三种操作可以进行,初始化、递减和增减,这三种操作都是原子操作。递增减都可以用于阻塞一个进程,增加操作可以用于接触阻塞一个进程。也称计数信号量或一般信号量
二元信号量:只取0和1的信号量
互斥量:类似于二元信号量,关键区别在于为其加锁的进程和为其解锁的进程必须为同一进程。
条件变量:一种数据类型,用于阻塞进程或者线程,直到特定条件为真。
管程:一种编程语言结构,在一个抽象数据类型中封装了变量、访问过程和初始化代码。管程的变量只能由管程自己的访问过程来访问,每次只能有一个进程在其中执行。访问过程即临界区。管程可以有一个等待进程队列。
事件标志:作为同步机制的一个内存字,应用程序代码可以为标志中的每个位关联不同的事件。通过测试相关的一个或多个位,线程可以等待一个或者多个事件。在全部所需的位都被设定或者至少一个位被设定之前线程会被一直阻塞。
信箱/消息:两个进程交换数据的方法,也用于同步
自旋锁:一种互斥机制,进程在一个无条件循环中等待,等待锁变量的值可用

生产者/消费者问题

简单描述:有一个或者多个生产者生产某种类型的数据,并放置在缓冲区;有一个消费者从缓冲去取出数据,每次取一项;系统保证避免对缓冲区的重复操作,也就是说,在任何时候只有一个主体(生产者或消费者)可以访问缓冲区。要确保这样的操作,当缓冲区已满时,生产者不会继续向其中添加数据;当缓冲区为空时,消费者不会从其中移走数据。

管程

信号量为实现互斥以及进程间的合作提供了一种原始的但功能强大且灵活的工具,但是,使用信号量设计一个正确的程序很困难,其难点在于semWait 和 semSingnal 操作可能分布在整个程序中,很难看出这些在信号量上的操作产生的整体效果。管程是一个程序设计语言结构,它提供与信号量相同的功能,但更容易控制。

消息传递

并发:死锁和饥饿

本节着重记录并发处理中常见的的两个问题:死锁和饥饿
死锁的三种常用方法:预防、检测和避免

死锁的原理

死锁可以定义为一组相互竞争资源或者进行通信的进程间永久的阻塞。当一组进程中的每个进程都在等待某个事件,而只有这组进程中的其他被阻塞的进程才能触发该事件,这时就称这组进程发生死锁。因为没有事件能够被触发,故死锁是永久性的。
可重用资源:
资源通常分为两类,可重用的和可消耗的。可重用资源是指一次只能提供一个进程安全的使用,并且不会由于使用而耗尽的资源。可重用资源的例子包括处理器、IO通道、内存和外存、设备以及诸如文件、数据库和信号量之类的数据结构。
可消耗资源:
可消耗资源是指可以被创建和销毁的资源。

资源分配图

刻画进程资源分配的有效工具是Holt引入的资源分配图。资源分配图是有向图,他阐述了系统资源和进程的状态,每个资源和进程用节点表示。

死锁的条件

死锁的三个必要条件:
1) 互斥,一次只有一个进程可以使用一个资源。其他进程不能访问已分配给其他进程的资源
2) 占有且等待,当一个进程等待其他进程时,继续占有已经分配的资源
3) 不可抢占,不能抢占进程已经占有的资源
4)循环等待,存在一个封闭的进程链,使得每个进程必须占有此链中下一个进程所需的一个资源

死锁的预防

一种是间接的死锁预防方法,防止出现前三个条件,另一种是直接的死锁预防,防止出现第四条

互斥

一般情况下是无法避免互斥的,即使允许多个对文件的读访问,但只允许互斥的写访问,即使这种情况下,如果多个进程要求写权限,也可能发生死锁

占有且等待

为预防占有且等待的条件,可以要求进程一次性的请求所有需要的资源,并且阻塞这个进程,直到所有请求同时满足。这种方法在两个方面是低效的。这也是应用程序在使用模块化程序设计或者多线程结构时产生的实际问题。为了同时请求所需资源,应用程序需要知道它以后将在所有级别或所有模块中请求的所有资源。

不可抢占

有几种方法可以抑制这个条件。可以放弃自身所占有的资源,或者要求被占有的资源的进程释放自身所占有的资源。总之,自己释放或者要求其余线程释放。

循环等待

通过定义资源类型的线性顺序来预防。例如一个进程如果分配了R资源,那么它接下来请求的资源只能是排在R类型后的资源类型。它同样会使资源类型变慢,并且可能在 没有必须的情况下拒绝资源访问。

死锁避免

与死锁预防不同的是,死锁预防会产生低效的资源使用和低效的进程执行的问题。死锁避免则是允许三个必要条件(互斥、非抢占和占有且等待),但通过明智的选择,确保永远不会达到死锁点。在死锁避免中,是否允许当前的资源分配请求是通过判断该请求是否可能导致死锁来决定的。因此,死锁避免需要知道将来的进程资源请求的情况。

进程启动拒绝

通过矩阵表达式和关系式,就可以定义一个避免死锁的策略:如果一个新进程的资源请求会导致死锁,则拒绝这个新进程。

资源分配拒绝

资源分配策略,又称为银行家算法。首先需要定义状态和安全状态的概念。考虑一个系统,他有固定的进程和固定数目的资源,任何时候一个进程可能分配到零个或者多个资源。系统状态是当前给进程分配的资源情况,因此,状态包含前面定义的两个向量Resource和Available以及两个矩阵Claim和Allocation。安全状态是至少有一个资源分配序列不会导致死锁,不安全状态当然是指一个不安全的状态。

死锁避免的限制

必须事先声明每个请求的最大资源数
考虑的进程必须是无关的,也就是说,他们执行的顺序必须没有任何同步的限制
分配资源的数目必须是固定的
在占有资源时,进程不能退出。

死锁检测

死锁预防是非常保守的,他们通过限制访问资源和进程上强加约束开解决死锁问题。与之相反,死锁检测不限制资源访问或者约束进程的行为,只要有可能,被请求的资源就被授权给进程。操作系统周期性的执行一个算法检测前面第四个条件(循环等待)。
死锁检查可以非常频繁的在每个资源请求时进行,也可以进行的少一些,具体取决于发生的可能性。在每次请求是检查死锁有两个好处:它使得可以尽早的检测死锁情况,并且由于此方法基于系统状态逐渐变化情况,因而算法相对比较简单。另一方面,这种频繁的检查会耗费相当多的处理器时间。

死锁检测算法

利用Allocation矩阵和Acailable向量来进行的算法检测

调度

操作系统必须为多个进程间可能有竞争关系的请求分配计算机资源。对处理器而言,可分配的资源是处理器上的执行时间,分配途径是调度。调度功能必须设计成可以满足多个目标,包括公平、任何线程都不会产生饥饿、有效的使用处理器时间以及较低的开销。此外,在启动或结束某些进程时,调度功能可能需要考虑不同的优先级和实时的期限。

处理器调度类型

处理器调度的目标是以满足系统目标(如响应 时间、吞吐率、处理器故障)的方式,把进程分配到一个或多个处理器中执行。在许多系统中,这个调度活动可以分成三个独立的功能:长程、中程和短程调度,他们的名字表名了在执行这些功能时出现的相对时间比例。
创建新的进程时,执行长程调度,它决定是否把当前进程添加到当前活跃的进程集合中。中程调度是交换功能的一部分,他决定是否把进程添加到那些至少部分在内存中并且可以被执行的进程集合中。短程调度真正决定下次执行哪一个就绪进程。

调度算法

短程调度准则
优先级的使用
选择调度策略
性能比较
公平共享调整

分布式系统

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值