操作系统的定义、特征、功能
定义
操作系统 是指控制和管理整个计算机系统的硬件和软件资源,并合理地组织调度计算机的工作和资源的分配,以提供给用户和其他软件方便的接口和环境,它是计算机系统中最基本的系统软件
计算机系统自下而上可粗分为四个部分:硬件、操作系统、应用程序和用户。操作系统管理各种计算机硬件,为应用程序提供基础,并充当计算机硬件和用户的中介
特征
操作系统的基本特征包括并发、共享、虚拟 和 异步
并发:指两个或多个事件在同一时间间隔内发生。这些事件宏观上是同时发生的,但微观上是交替发生的
操作系统的并发性指计算机系统中同时存在着多个运行着的程序。
一个单核处理机(CPU)同一时刻只能执行一个程序,因此操作系统会负责协调多个程序交替执行(这些程序微观上是交替执行的,但宏观上看起来就像在同时执行)
共享 即资源共享,是指系统中的资源可供内存中多个并发执行的进程共同使用。
共享可以分为以下两种资源共享方式。
1)互斥共享方式
系统中的某些资源(临界资源),虽然可以提供给多个进程使用,但一个时间段内只允许一个进程访问该资源。如打印机、磁带机在同一段时间内只允许一个进程方位该资源,伺候若再有其他进程也要访问该资源,则必须等待。
2)同时访问方式
系统中还有一种资源,允许在一段时间内由多个进程“同时”对它进行访问。这里所谓的“同时”往往是宏观上的,而在微观上,这些进程可能是交替的对该资源进行访问即“分时共享”。典型的可供多个进程同时访问的资源是磁盘设备。
生活实例:
互斥共享方式:使用QQ和微信视频。同一时间段内摄像头只能分配给其中一个进程。
同时共享方式:使用QQ发送文件A,同时使用微信发送文件B。宏观上看,两边都在同时读取并发送文件,
说明两个进程都在访问硬盘资源,从中读取数据。微观上看,两个进程是交替着访问硬盘的。
并发和共享是操作系统两个最基本的特征,这两者之间又是互为存在条件的:
1资源共享是以程序的并发为条件的,若系统不允许程序并发执行,则自然不存在资源共享的问题
2若系统不能对资源共享实施有效地管理,也必将影响到程序的并发执行,甚至根本无法并发执行。
虚拟 虚拟是指把一个物理上的实体变为若干个逻辑上的对应物。物理实体是实的,即实际存在的;而后者是虚的,是用户感觉上的事物
操作系统的虚拟技术可归纳为:时分复用技术 和 空分复用技术。
空分复用技术, 如虚拟存储技术。
空分复用技术,如 在虚拟处理器技术中,是通过多道程序设计技术,让多道程序并发执行的方法,来分时使用一台处理器的。此时,虽然只有一台处理器,但他能同时为多个用户服务,是每个终端用户都认为是有一个中央处理器在为他服务。利用多道程序设计技术,把一台物理上的CPU虚拟为多台逻辑上的CPU,称为虚拟处理器。
异步 在多道程序环境下,允许多个程序并发执行,但由于资源有限,进程的执行不是一贯到底,而是走走停停,以不可预知的速度向前推进,这就是进程的异步性。
功能
处理器管理
在多道程序环境下,处理器的分配和运行都是以进程为基本单位,因而对处理器的管理可归结为对进程的管理。进程管理的主要功能有:进程控制,进程同步,进程通信,死锁处理,处理器调度等。
存储器管理
存储器管理的主要任务是位多通道程序的运行提供良好的环境,方便用户使用以及提高内存的利用率。因此,存储器管理应具备:内存分配、地址映射、内存保护与共享和内存扩充等。
文件管理
文件管理主要包括文件的存储空间管理、目录管理及文件读写管理及保护等。
设备管理
设备管理的主要任务就是完成用户的IO请求,方便用户使用各种设备,并提高设备的利用率,主要包括混充管理、设备分配、设备处理和虚拟设备等功能。
用户接口
操作系统提供的接口主要分为两类:一类是命令接口,用户利用这些操作命令来组织和控制作业的执行;另一类是程序接口,编程人员可以使用它们来请求操作系统服务。
进程管理
进程的定义与组成
进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位。
进程(进程实体)由程序段、数据段、PCB三部分组成。
进程的状态与转换
进程有三种基本状态
运行状态:进程正在处理器上运行。在单处理器的环境下,每一时刻最多只有一个进程处于运行状态。
就绪状态:进程已处于准备运行的状态,即进程获得了除CPU之外的一切所需资源,一旦得到处理器即可运行。
阻塞状态:又称为等待状态:进程正在等待某一事件而暂停运行,如等待某资源为可用(不包括处理器),或等待输入输出的完成。及时处理器空闲,该进程也不能运行。
就绪状态和等待状态的区别:就绪状态是指进程仅缺少处理器,只要获得处理器资源就立即执行;而等待状态是指进程需要其他资源或等待某一事件,即使处理器空闲也不能运行。
除此以外还有两个状态
创建状态:进程正在被创建,尚未转到就绪状态。创建进程通常需要多个步骤:首先申请一个空白的PCB,并向PCB中填写一些控制和管理进程的信息;然后由系统为该进程分配运行时所必须的资源;最后把该进程转入到就绪状态。
结束状态:进程正在从系统中消失,这可能是进程正常结束或其他原因中断退出运行。当进程需要结束运行时,系统首先必须置该进程为结束状态,然后再进一步处理资源释放和回收工作。
进程控制
进程控制就是对系统中所有进程从创建到消亡的全过程实施有效的控制。简化理解:进程控制就是要实现进程状态转换。
在操作系统中,一般把进程控制用的程序段成为原语,原语的特点是执行期间不允许中断,他是一个不可分割的基本单位。
这种不可被中断的操作即原子操作。
原语采用“关中断指令”和“开中断指令”实现
关/开中断指令的权限非常大,必然是只允许在核心态下执行的特权指令
操作系统创建一个新进程的过程 (创建原语):
- 为新进程分配一个为我一个进程标示号,并申请一个空白的PCB。
- 为进程分配资源,为新进程的程序和数据,以及用户占分配必要的空间。
- 初始化PCB,主要包括初始化标识信息、初始化处理器状态信息和初始化处理器控制信息,以及设置进程的空闲及。
- 如果进程就绪队列能够接纳新进程,就将新进程插入到就绪队列,等待被调度运行。
操作系统终止进程的过程(撤消原语):
- 根据被终止进程的标示符,检索PCB,从中读出该进程的状态。
- 若被终止进程处于执行状态,立即终止该进程的执行,将处理器资源分配给其他进程。
- 若该进程还有子进程,则应将其所有子进程终止。
- 将该进程所拥有的资源、或归还给父进程或归还给操作系统。
- 将该PCB从所在队列(链表)中删除。
线程
为什么要引入线程?
有的进程可能需要“同时”做很多事,而传统的进程只能串行地执行一系列程序。为此,引入了“线程”,来增加并发度。
线程与进程
- 线程是程序执行的最小单位,而进程是操作系统分配资源的最小单位
- 进程间切换,需要切换进程的运行环境,系统开销很大。线程间并发,如果是同一进程内的线程切换,则不需要切换进程环境,系统开销小。因为 同一进程的不同线程间共享进程的资源
线程的属性:
- 线程是处理机调度的单位
- 多CPU计算机中,各个线程可占用不同的CPU
- 每个线程都有一个线程ID、线程控制块(TCB)
- 线程也有就缩、阻塞、运行三种基本状态
- 线程几乎不拥有系统资源
- 同一进程的不同线程间共享进程的资源
- 由于共享内存地址空间,同一进程中的线程间通信甚至无需系统干预
- 同一进程中的线程切换,不会引起进程切换
- 不同进程中的线程切换,会引起进程切换
- 切换同进程内的线程,系统开销很小
- 切换进程,系统开销较大
进程同步/互斥
什么是进程同步?
进程具有异步性的特征。异步性是指,各并发执行的进程以各自独立的、不可预知的速度向前推进。
同步亦称直接制约关系,它是指为完成某种任务而建立的两个或多个进程,这些进程因为需要在某些位置上协调它们的工作次序而产生的制约关系。进程间的直接制约关系就是源于它们之间的相互合作。
什么是进程互斥?
进程的“并发”需要“共享”的支持。各个并发执行的进程不可避免的需要共享一些系统资源(比如内存,又比如打印机、摄像头这样的I/O设备)
对临界资源的访问,必须互斥地进行。互斥,亦称间接制约关系。进程互斥指当一个进程访问某临界资源时,另一个想要访问该临界资源的进程必须等待。当前访问临界资源的进程访问结束,释放该资源之后,另一个进程才能去访问临界资源。
临界资源
一个时间段内只允许一个进程使用的资源称为临界资源。许多物理设备(比如摄像头、打印机)都属于临界资源。此外还有许多变量、数据、内存缓冲区等都属于临界资源。
信号量机制
用户进程可以通过使用操作系统提供的一对原语来对信号量进行操作,从而很方便的实现了进程互斥、进程同步。
信号量 其实就是一个变量(可以是一个整数,也可以是更复杂的记录型变量),可以用一个信号量来表示系统中某种资源的数量,比如:系统中只有一台打印机,就可以设置一个初值为1的信号量。
原语是一种特殊的程序段,其执行只能一气呵成,不可被中断。原语是由关中断/开中断指令实现的。
一对原语:wait(S)原语和signal(s)。原语wait、signal 原语常简称为P、V操作(来自荷兰语 proberen和verhogen)。因此,做题的时候常把wait(S)、signal(S)两个操作分别写为P(S)、V(S)
可以把原语理解为我们自己写的函数,函数名分别为wait和signal,括号里的信号量s其实就是函数调用时传入的一个参数。
整型信号量
用一个整数型的变量作为信号量,用来表示系统中某种资源的数量。
int S = 1; //初始化整型信号量S,表示当前系统中可用打印机资源数
void wait(int S){ //wait源于,相当于“进入区”
while(s<=0); // 如果资源数不够,就一直等待循环
S--; //如果资源数够,则占用一个资源
}
void signal(S){ //signal原语,相当于“退出区”
S++; //使用完资源后,在退出区释放资源
}
与普通整数变量的区别:
- 对信号量的操作只有三种,即“初始化、P操作、V操作”
- “检查”和“上锁”一气呵成,避免了并发、异步导致的问题
- 不满足”让权等待“原则,会发生”忙等“
记录型信号量
整型信号量的缺陷是存在“忙等”问题,因此人们又提出了“记录型信号量”,即用记录型数据结构表示的信号量。
/*记录型信号量的定义*/
typedef struct {
int value; //剩余资源数
struct process *L; //等待队列
} semaphore;
/*某进程需要使用资源时,通过wait原语申请*/
void wait (semaphore S) {
S.value --;
if (S.value < 0) {
block(S,L);
//如果剩余资源数不够,使用block原语使进程从运行态进度阻塞态,
//并把挂到信号量S的等待队列(阻塞队列)中
}
}
/*进程使用完后,使用signal原语释放*/
void signal (semaphore S) {
s.value ++;
if(S.value <= 0) {
wakeup(S,L); //释放资源后,若还有别的进程在等待这种资源,
//则使用wakeup原语唤醒等待队列中的一个进程,该进程从阻塞态变为就绪态
}
}
- wait(S)、signal(S)也可以记为P(S)、V(S),这对原语可用于实现对系统资源的“申请”和“释放”
- S.value 的初值表示系统中某种资源的数目
- 对信号量S的一次P操作意味着进程请求一个单位的该类资源,因此需要执行S.value--,表示资源数减1,当S.value<0 时表示该类资源已分配完毕,因此进程应调用block原语进行自我阻塞(当前运行的进程从运行态 →阻塞态),主动放弃处理机,并插入该类资源的等待队列S.L中。可见,该机制遵循了“让权等待”原则,不会出现“忙等”现象。
- 对信号量S的一次V操作意味着进程释放一个单位的该类资源,因此需要执行S.value++,表示资源数加1,若加1后仍是S.value<=0,表示依然有进程在等待该类资源,因此应调用wakeup原语唤醒等待队列中的第一个进程(被唤醒进程从阻塞态->就绪态)。
记录型信号量需要自己推断在什么条件下需要执行block 或 wakeup
例题
答案 D
设有n个进程共享一个互斥段,对于如下两种情况使用信号量,信号量的值的变化怎样?
(1) 如果每次只允许一个进程进入互斥段。
(2) 如果每次最多允许m个进程(m<n)同时进入互斥段。
(1)互斥信号量初值为 1 ,变化范围为[ -n + l , 1 ]。
(2)互斥信号量初值为 m ,变化范围为[ -n + m , m ]。
P、V操作
P操作表示申请一个资源、V操作表示释放一个资源。
P操作定义:S:=S-1,若S≥0,则执行P操作的进程继续执行;否则,若S<0,则设置该进程为阻塞状态(因为无可用资源),并将其插入阻塞队列。
V操作定义:S:=S+1,若S>0,则执行V操作的进程继续执行;否则,若S≤0,则从阻塞状态唤醒一个进程,并将其插入就绪队列,执行V操作的进程继续执行。
实现进程互斥
- 分析并发进程的关键活动,划定临界区
- 设置互斥信号量mutex,初值为1
- 在临界区之前执行P(mutex)
- 在临界区之后执行V(mutex)
实现进程同步
- 分析什么地方需要实现“同步关系”,即必须保证“一前一后”执行的两个操作(或两句代码)
- 设置同步信号量s,初始为0
- 在“前操作”之后执行V(S)
- 在“后操作”之前执行P(S)
实现前驱关系
进程P1中有句代码S1,P2中有句代码S2...P3...P6中有句代码S6。这些代码要求按如下前驱图所示的顺序来执行:
其实每一对前驱关系都是一个进程同步问题(需要保证一前一后的操作)因此:
- 要为每一对前驱关系各设置一个同步变量
- 在“前操作”之后对相应的同步变量执行V操作
- 在“后操作”之前对相应的同步变量执行P操作
死锁
在并发环境下,各进程因竞争资源而造成的一种互相等待对方手里的资源,导致各进程都阻塞,都无法向前推的现象,就是"死锁"。发生死锁后若无外力干涉,这些进程都将无法向前推进。
死锁产生的必要条件
产生死锁必须同时满足一下四个条件,只要其中任一条件不成立,死锁就不会发生。
互斥条件∶只有对必须互斥使用的资源的争抢才会导致死锁(如哲学家的筷子、打印机设备)。像内存、扬声器这样可以同时让多个进程使用的资源是不会导致死锁的(因为进程不用阻塞等待这种资源)。
不剥夺条件∶进程所获得的资源在未使用完之前,不能由其他进程强行夺走,只能主动释放。
请求和保持条件∶进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源又被其他进程占有,此时请求进程被阻塞,但又对自己已有的资源保持不放。
循环等待条件∶存在一种进程资源的循环等待链,链中的每一个进程已获得的资源同时被下一个进程所请求。
注意!发生死锁时一定有循环等待,但是发生循环等待时未必死锁(循环等待是死锁的必要不充分条件)
如果同类资源数大于1,则即使有循环等待,也未必发生死锁。但如果系统中每类资源都只有一个,那循环等待就是死锁的充分必要条件了。
死锁的处理策略
- 预防死锁。破坏死锁产生的四个必要条件中的一个或几个。
- 避免死锁。用某种方法防止系统进入不安全状态,从而避免死锁(银行家算法)
- 死锁的检测和解除。允许死锁的发生,不过操作系统会负责检测出死锁的发生,然后采取某种措 施解除死锁。
预防死锁
破坏互斥条件:如果把只能互斥使用的资源改造为允许共享使用,则系统不会进入死锁状态。比如∶spooling技术。操作系统可以采用spooling技术把独占设备在逻辑上改造成共享设备。比如,用spooling技术将打印机改透为共享设备。
破坏不剥夺条件:
- 不剥夺条件∶进程所获得的资源在未使用完之前,不能由其他进程强行夺走,只能主动释放。
- 破坏不剥夺条件的方法∶
- 方案一∶当某个进程请求新的资源得不到满足时,它必须立即释放保持的所有资源,特以后需要时再重新申请。也就是说,即使某些资源尚未使用完,也需要主动释放,从而破环了不可剥夺条件。
- 方案二∶当某个进程需要的资源被其他进程所占有的时候,可以由操作系统协助,将想要的资源强行菊乔,这种方式一般需要考虑各进程的优先级(比如∶剥夺调度方式,就是将处理机资源强行剥 夺给优先级更高的进程使用)
破坏请求和保持条件 :
-
请求和保持条件∶进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源又被其他进程占有,此时请求进程被阻塞,但又对自己已有的资源保持不放。
-
可以采用静态分配方法,即进程在运行前一次申请完它所需要的全部资源,在它的资源未满足前,不让它投入运行。一旦投入运行后,这些资源就一直归它所有,该进程就不会再请求别的任何资源了.
破坏循环等待条件 :可采用顺序资源分配法。首先给系统中的资源编号,规定每个进程必须按编号递增的顺序请求资源,同类资源(即编号相同的资源)一次申请完。
死锁的检测和解除
资源请求图
蓝色圆圈表示进程。
用矩形表示资源结点,矩形中的小圆代表该类资源的数量
由资源结点指向进程的剪头表示:进程已经分配到的资源数量。一条边表示资源点已经分配了一个资源給进程。
由进程指向资源结点的剪头表示:进程还需要的资源数量。一条边表示进程还要向资源节点申请一个资源。
为了能对系统是否已发生了死锁进行检测,必须∶
- 用某种数据结构来保存资源的请求和分配信息 (邻接表、邻接矩阵)
- 提供一种算法,利用上述信息来检测系统是否已进入死锁状态。
**** 死锁的检测
P1 进程向R2申请1个资源,R2还剩1个资源,所以R2是可以满足P1进程的。P1进程可以执行下去,所以 P1 是非阻塞节点。相反P2进程,必须要等P1进程执行完以后,P1释放了R1占用的资源,P2进程才会开始执行,所以P2是阻塞节点。
当P1执行完以后,跟进程P1相连的请求边和分配边都可以消除。如下图。
P1执行完以后,P2可以顺利执行,消去和P2相连的请求边和分配边。如下图。
如果按上述过程分析,最终能消除所有边,就称这个图是可完全简化的。此时一定没有发生死锁(相当于能找到一个安全序列)。