一、操作系统概述
特性
1. 并发: 同一时间间隔内支持执行多个任务, 对于一个核则是交替执行;
2. 共享: 硬件资源或数据资源支持多个进程共享;
3. 异步: 并发情况下, 一个程序会陆陆续续被执行,完成时间不可预知;
4. 虚拟: 物理实体转化为逻辑实体,如虚拟内存。
基本功能
- CPU管理:对处理器的管理和调度最终归结为对进程和线程的管理和调度,包括进程控制和管理,线程控制和管理,确定处理器调度策略,设计处理器调度算法,做好处理器分配和回收。
- 存储管理:存储管理的主要任务是管理内存资源,为多道程序运行提供有力支撑,提高存储空间利用率,具体来说有内存分配与回收,地址转换与存储保护,内存共享与存储扩充等。
- 设备管理:设备管理的除妖任务是管理各种外部设备,完成用户提出的I/O请求;加快数据传输速度,发挥设备的并行性,提高设备的利用率;提供设备驱动程序和中断处理请求。
- 文件管理:文件库案例的主要任务有提供文件逻辑组织方法,提供文件物理组织方法,提供文件存取和使用方法,实现文件目录管理,实现文件共享和安全性控制,实现文件存储空间管理等。
体系结构
- 大内核:将操作系统作为一个整体放在内核当中。
- 微内核:将操作系统的功能进行详细划分,只有微内核在内核态中存在,其他的在用户态。由于存在用户态和内核态的切换所以会影响系统整体性能。
补充
用户栈: 进程在用户空间时创建的栈,比如函数调用时压栈出栈, 保存了函数互相调用的参数/返回值等;
内核栈: 中断进入内核态时,用内核栈来保存用户态进程的状态信息,返回用户钛再将这些信息出栈;内核栈位置在内核的一块固定区域,保存中断现场,进程调用数据等。
运行机制
中断:外中断(强迫中断,包括了人为干预、外部设备请求,时钟中断);内中断(自愿中断:指令中断,强迫中断:硬件或者软件故障)。
异常:
系统调用概念:一个进程在用户态想使用内核态的功能时,就需要进行系统陷入内核状态,其过程由操作系统完成。
常见的linux系统调用
Linux系统调用包括:
进程控制:fork(); wait();阻塞 exit();
进程通信:pipe();管道 shmget(); mmap(); 文件地址映射
文件操作:open(); read(); write();
设备操作:ioctrl(); read(); write();
信息维护:getpid(); alarm(); sleep();
安全:chmod(); 改变文件访问权限 umask(); chown();
那么我们主要围绕这进程管理和内存管理的基本功能来进行整理。
二、进程管理
进程与线程
进程:资源分配的基本单位,进程控制块(PCB)记录进程的基本信息和运行状态。程序会调用一个或多个进程。
线程:独立调度的基本单位,一个进程中有多个线程占有共有资源。
进程的状态和转换
创建-就绪-运行-阻塞-终止。
注意:只有就绪状态和运行状态之间存在回路。就绪状态通过进程调度算法获得CPU时间,转为运行态。而运行状态在CPU时间用完之后会转为就绪状态,等待下一次调度。阻塞状态是缺少资源从而由运行状态到阻塞状态转换而来,不包括CPU时间。特别是没有CPU时间会从运行状态转移到就绪状态。
进程控制块
进程控制块是进程存在的唯一标识,是操作系统用来记录和刻画进程状态及环境信息的数据结构,是进程动态特征的汇集,也是操作系统掌握进程的唯一资料结构和管理进程的主
要依据。
(1)标识信息:标识信息用于唯一地标识一个进程,分为用户使用的外部标识符合系统使用的内部标识号。
(2)现场信息:现场信息用于保存进程在运行时存放在处理器现场中的各种信息。
(3)控制信息:控制信息用于管理和调度进程
进程通信(共享存储系统、消息传递系统、管道通信)
- 管道( pipe ):
管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。有名管道(named pipe)也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。 - 信号量( semophore ):
信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。 - 消息队列( message queue ):
消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。 - 信号( signal ):
信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身;linux除了支持Unix早期信号语义函数sigal外,还支持语义符合Posix.1标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数)。 - 共享内存( shared memory ):
共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。 - 套接字( socket ):套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。
进程与线程的区别
-
地址空间:进程中线程共享进程的地址空间;而进程有自己的地址空间。
-
资源拥有:进程是资源分配和拥有的单位;而同一进程中的线程共享进程的资源。(各线程有自己的程序计数器、寄存器、堆栈、状态)
-
进程是资源分配的基本单位;线程是处理器调度的基本单位。
-
占有资源:进程是资源分配的基本单位,线程不拥有独立的资源,可访问在独立进程下的资源。
-
调度:线程是调度的基本单位,同一进程之间的线程是不引起进程的切换,进程切换会引起切换。
-
系统开销:进程(资源回收)之间的调度会花费比线程(寄存器信息存储)多的资源空间。
-
通信方面:进程通信需要用到:互斥和同步。线程通信需要创建全局变量。
-
为什么要引入线程?
进程是资源拥有者。在创建、切换和撤销的操作需要较大的时空开销,限制了并发程度的进一步提高。引入线程将进程作为资源分配单位和资源调度单位这两个属性分开处理。进程任作为资源分配的基本单位;把调度执行和切换的任务交给线程。
进程调度算法
- 批处理系统:先来先服务(FIFO)、短作业优先、最短剩余时间按优先。
- 交互式处理系统:时间片轮转、队列优先级调度、多级反馈机制。
- 实时系统:硬实时(在规定时间内完成任务,不允许有误差,计算精度高的处理任务)、软实时(在规定时间内可以有延迟,订票)。
典型的调度算法(先来先服务、短作业优先、时间片轮转、优先级、高响应比、多级反馈队列调度算法)
- 先来先服务(FCFS , First Come First Served) 特点:适合长作业,不利于段作业;适合CPU繁忙型作业,不利于I/O繁忙型作业。
- 短作业优先(SJF, Shortest Job First) 特点:提高了系统吞吐量;对长作业不利,有可能长时间得不到执行。
- 优先级调度(HPF , Highest Priority First) 特点:进程调度每次将处理机分配给具有最高优先级的就绪进程。最高优先级算法可与不同的CPU方式结合形成“可抢占式”最高优先级算法和“不可抢占式”最高优先级算法。常用于批处理系统。
- 高响应比优先(HRN,Highest Response_ratio Next) 特点:HRN是对FCFS方式和SJF方式的一种综合平衡。 响应比R=(W + T)/ T . 其中W为等待时间,T为需要执行时间。
- 时间片轮转算法(RR,Round Robin) 特点:时间片轮转调度是一种最古老,最简单,最公平且使用最广的算法。将CPU的处理时间划分成一个个的时间片,就绪队列中的进程轮流运行一个时间片。当时间片结束时,就强迫进程让出CPU,该进程进入就绪队列,等待下一次调度,同时,进程调度又去选择就绪队列中的一个进程,分配给它一个时间片,以投入运行。
- 多级队列轮转算法:几种调度算法的结合形式多级队列方式。
同步与互斥
进程同步的基本概念
临界资源:一次只允许一个进程使用。
同步和互斥:同步多个进程依次执行,互斥多个进程只有一个进程进入临界区。
信号量:down阻塞,P操作;up唤醒,V操作。
2、实现临界区互斥的基本方法(软件实现方法、硬件实现方法)
3、信号量
4、管程
经典同步问题
- 生产者-消费者问题、
- 读者-写者问题、
- 哲学家进餐问题
死锁
死锁的概念
如果在一个进程集合中的每个进程都在等待只能由该集合中的其它一个进程才能引发的事件,而无限期陷入僵持的局面称为死锁
如:假如双方都拥有部分资源(P1拥有A,P2拥有B,且A,B均只有一个),但这时P1还需要B,P2还需要A,于是P1与P2都会处在无限等待状态,发生了死锁。
补充:饥饿
饥饿是指一个进程由于其它进程总是优先于它而被无限期拖延
考虑一台打印机分配的例子,当有多个进程需要打印文件时,系统按照短文件优先的策略排序,该策略具有平均等待时间短的优点,似乎非常合理,但当短文件打印任务源源不断时,长文件的打印任务将被无限期地推迟,导致饥饿
死锁的条件
互斥、占有和等待、不抢占、环路等待。
死锁预防
破坏互斥、破坏占有和等待、破坏不抢占和破坏环路等待。
死锁避免
安全状态:不发生死锁而且进程要求的进程请求最大。单银行家资源算法,多银行家资源算法。
死锁检测与解除
鸵鸟策略(忽视);死锁检测和恢复(检测:有向环路检测,满足环路即死锁;每种类型多个资源检测:未被标记发生死锁。恢复:抢占,回滚,杀死进程)
线程同步
- 几种方式
- 互斥锁:提供对临界资源的保护,当多线程试图访问临界资源时,都必须通过获取锁的方式来访问临界资源。(临界资源:是被多线程共享的资源)
- 条件变量:提供线程之间的一种通知机制,当某一条件满足时,线程A可以通知阻塞在条件变量上的线程B,B所期望的条件已经满足,可以解除在条件变量上的阻塞操作,继续做其他事情。
- 信号量:提供对临界资源的安全分配。如果存在多份临界资源,在多个线程争抢临界资源的情况下,向线程提供安全分配临界资源的方法。如果临界资源的数量为1,将退化为锁。
内存池,进程池,线程池
1、池的概念 由于服务器的硬件资源“充裕”,那么提高服务器性能的一个很直接的方法就是以空间换时间,即“浪费”服务器的硬件资源,以换取其运行效率。这就是池的概念。池是一组资源的集合,这组资源在服务器启动之初就完全被创建并初始化,这称为静态资源分配。当服务器进入正是运行阶段,即开始处理客户请求的时候,如果它需要相关的资源,就可以直接从池中获取,无需动态分配。很显然,直接从池中取得所需资源比动态分配资源的速度要快得多,因为分配系统资源的系统调用都是很耗时的。当服务器处理完一个客户连接后,可以把相关的资源放回池中,无需执行系统调用来释放资源。从最终效果来看,池相当于服务器管理系统资源的应用设施,它避免了服务器对内核的频繁访问。 池可以分为多种,常见的有内存池、进程池、线程池和连接池。
2、内存池 c++内存分配优先使用内存池,而不是new,delete。 new和delete首先会转调用到malloc和free,这个大家应该很熟识了。很多人认为malloc是一个很简单的操作,其实巨复杂,它会执行一个系统调用(当然不是每一次,windows上是按页算),该系统调用会锁住内存硬件,然后通过链表的方式查找空闲内存,如果找到大小合适的,就把用户的进程地址映射到内存硬件地址中,然后释放锁,返回给进程。如果在多线程环境下,进程内的分配也会上锁,跟上面类似,不过不是以页,而是以分配的内存为单位。
内存池就是预先分配好,放到进程空间的内存块,用户申请与释放内存其实都是在进程内进行,SGI-STL的alloc遇到小对象时就是基于内存池的。只有当内存池空间不够时,才会再从系统找一块很大的内存。 所以使用内存池提升了内存分配与回收的效率。
3、进程池与线程池 进程池和线程池相似,所以这里我们以进程池为例进行介绍。如没有特殊声明,下面对进程池的讨论完全是用于线程池。 进程池是由服务器预先创建的一组子进程,这些子进程的数目在3~10个之间(当然这只是典型情况)。线程池中的线程数量应该和CPU数量差不多。进程池中的所有子进程都运行着相同的代码,并具有相同的属性,比如优先级、PGID等。当有新的任务来到时,主进程将通过某种方式选择进程池中的某一个子进程来为之服务(如使用随机算法或轮转法来挑选一个子进程)。当选择好子进程后,主进程还需要使用某种通知机制来告诉目标子进程有新任务需要处理,并传递必要的数据。最简单的方式是,在父进程和子进程之间预先建立好一条管道,然后通过管道来实现所有的进程间通信。在父线程和子线程之间传递数据就要简单得多,因为我们可以把这些数据定义为全局,那么它们本身就是被所有线程共享的。
三、内存管理
包括内存管理和虚拟内存管理。
内存管理包括内存管理概念、交换与覆盖、连续分配管理方式和非连续分配管理方式(分页管理方式、分段管理方式、段页式管理方式)。
虚拟内存管理包括虚拟内存概念、请求分页管理方式、页面置换算法、页面分配策略、工作集和抖动。
内存管理的基础
基本功能
1、 内存空间的分配与回收,包括内存的分配和共享。
2、地址转换,把逻辑地址转换成相应的物理地址。
3、内存空间的扩充,利用虚拟技术或自动覆盖技术,从逻辑上扩充内存。
4、存储保护,保证各道作业在各自存储空间内运行,互不干扰。
进程运行原理
在进行具体的内存管理之前,需要了解进程运行的基本原理和要求。
1、创建进程
首先要将程序和数据装入内存。将用户原程序变成可在内存中执行的程序,通常需要以下几个步骤。
1、编译,由编译程序将用户源代码编译成若干个目标模块。
2、链接,由链接程序将编译后形成的一组目标模块,以及所需库函数链接,形成完整的装入模块。
3、装入,由装入程序将装入模块装入内存。
2、覆盖与交换
覆盖与交换技术是在多道程序环境下用来扩充内存的两种方法。覆盖技术主要用在早期的操作系统中,而交换技术则在现代操作系统中仍具有较强的生命力。
- 覆盖基本思想是:由于程序运行时并非任何时候都要访问程序和数据的各个部分,因此可以把用户空间分成一个固定区和若干个覆盖区。将经常活跃的部分放在固定区,其余部分按调用关系分段。首先将那些将要访问的段放入覆盖区,其他段放在外存中,在需要调用时,系统再将其掉入覆盖区,替换其中原有的段。
- 交换的基本思想是:把处于等待状态(或在CPU调度原则下被剥夺运行权利)的进程从内存移到辅存,把内存空间腾出来,这一过程又叫换出;把准备好竞争CPU运行的进程从辅存移到内存,这一过程又称为换入。
3、连续分配管理方式
连续分配方式,是指为一个用户程序分配一个连续的内存空间。它主要包括单一连续分配、固定分区分配和动态分区分配。
4、非连续分配管理方式
非连续分配方式允许一个程序分散的装入不相邻的内存分区中,根据分区的大小是否固定分为分页存储管理方式和分段存储管理方式。
分页存储管理方式中,又根据运行作业时是否要把作业的所有页面都装入内存才能运行分为基本分页存储管理和请求分页存储管理方式。
固定分区会产生内部碎片,动态分区会产生外部碎片,两种技术对内存的利用率都比较低。我们希望内存的使用能尽量避免碎片的产生,这就引出了分页思想:把主存空间划分为大小相等且固定的块,块相对较小,作为主存的基本单位。每个进程也以块为单位进行划分,进程在执行时,以块为单位逐个申请主存中的块空间。
1)分页存储的几个基本概念
a. 1页面和页面大小。进程中的块称为页,内存中的块称为页框。外存也以同样单位划分,直接称为块。进程在执行时需要申请主存空间,就是要为每个页面分配主存中的可用页框,这就产生了页和页框的一一对应。
为了方便地址转换,页面大小应是2的整数幂。同时页面大小应当适中。如果页面太小,会是进程的页面数过多,这样页表就过长,占用大量内存,而且也会增加硬件地址转换的开销,降低页面换入换出的效率。页面过大又会是页面碎片过大,降低内存利用率。所以页面的大小应该适中,考虑到空间效率和时间效率。
b. 地质结构。分页存储管理的地质结构包含两部分:前一部分为页号,后一部分为页内偏移量W。地址长度为32位,其中011为页内地址,即每页大小为4kB;1231位为页号,地址空间最多允许有2 20页。
c. 页表。为了便于在内存中找到进程的每个页面所对应的物理块,系统为每个进程建立一张页表,记录页面在内存中对应的物理块号,页表一般存放在内存中。
在配置了页表后,进程执行时,通过查找该表,即可找到每页在内存中中的物理块号。可见,页表的作用是实现从页号到物理块号的地址映射。
2)基本地址变换机构
地址变换机构的任务是将逻辑地址中的页号,转换为内存中物理块号,地址变换是借助于页表实现的。
逻辑地址到物理地址的变换过程如下:
1地址变换机构自动将有效地址分为页号和页内偏移量两部分,再用页号去检索页表。在执行检索之前,先将页号与页表长度比较,如果页号大于或等于页表长度,则表示地址越界并中断。
2若未越界,则将页表始址与页号和页表项长度的乘积相加,便得到该表项在页表中的位置,于是可从中得到该页的物理块号。
3与此同时,在将有效地址中的页内偏移量送入物理地址寄存器的块内地址字段中。
以上整个地址变换过程均是由硬件自动完成的。
虚拟内存管理
要真正理解虚拟内存技术的思想,首先必须了解计算机中著名的局部性原理。著名的Bill Joy说过:“在研究所的时候, 我经常开玩笑的说高速缓存是计算机科学中唯一重要的思想。
局部性原理表现在以下两个方面:
1)时间局部性。如果程序中的某条指令一旦执行,则不久以后该指令可能再次执行;如果某数据被访问过,则不久以后该数据可能再次被访问。产生时间局部性的典型原因,是由于在程序中存在着大量的循环操作。
2)空间局部性。一旦程序访问量某个存储单元,在不久之后,其附近的存储单元也将被访问,即程序在一段时间内所访问的地址,可能集中在一定的范围之内,其典型情况便是程序的顺序执行。
时间局部性是通过将进来使用的指令和数据保存到高速缓存存储器中,并使用高速缓存的层次结构实现。空间局部性通常是使用较大的高速缓存,并将预取机制集成到高速缓存控制逻辑中实现。虚拟内存技术实际上就是建立了“内存-外存”的两级存储器的结构,利用局部性原理实现高速缓存。
基于局部性原理,在程序装入时,可以将程序的一部分装入内存,而将其与部分留在外存,就可以启动程序执行。在程序执行过程中,当所访问的信息不在内存时,由操作系统将所需要的部分调入内存,然后继续执行程序。另一方面,操作系统将内存中暂时不使用的内容换到外存上,从而腾出空间存放将要调入内存的信息。这样,计算机好像为用户提供了一个比实际内存大的多的存储器,成为虚拟存储器。
虚拟存储器有以下三个主要特征:
1)多次性,是指无需在作业运行时一次性地全部装入内存,而是允许被分成多次调入内存运行。
2)对换性,是指无需在作业运行时一直常驻内存,而是允许在作业的运行过程中,进行换进和换出。
3)虚拟性 ,是指从逻辑上扩充内存的容量,是用户所看到的内存容量,远大于实际的内存容量。
虚拟内存中,允许讲一个作业分多次调入内存。采用连续分配方式时,会是相当一部分内存空间都处于暂时或永久的空闲状态,造成内存资源的严重浪费,而且也无法从逻辑上扩大内存容量。因此,虚拟内存的实现需要建立在离散分配的内存管理方式的基础上。
虚拟内存的实现有以下三种方式:
l 请求分页存储管理
l 请求分段存储管理
l 请求段页式存储管理
不管哪种方式,都需要有一定的硬件支持。一般需要的支持有以下几个方面:
l 一定容量的内存和外存。
l 页表机制或段表机制,作为主要的数据结构。
l 中断机构,当用户程序要访问的部分尚未调入内存,则产生中断。
l 地址变换机构,逻辑地址到物理地址的变换。
2、请求分页管理方式
3、页面置换算法
4、页面分配策略
5、抖动和工作集
在进程的页面置换过程中,频繁的页面调度行为成为抖动,或颠簸。如果一个进程在换页上用的时间多于执行时间,那么这个进程就在颠簸。
在进程的页面置换过程中,频繁的页面调度行为成为抖动,或颠簸。如果一个进程在换页上用的时间多于执行时间,那么这个进程就在颠簸。
使用虚拟内存技术,操作系统中进程通常只有一部分块位于主存中,从而可以在内存中保留更多的进程以提高系统效率。此外,由于未用到的块不需要换入换出内存,因为节省了时间。但是系统必须很“聪明”地管理页面分配方案。在稳定状态,几乎主存的所有空间都被禁成块占据,处理器和操作系统可以直接访问到尽可能多的进程。但如果管理不当,系统发生抖动现象,处理器的大部分时间都将用于交换快,及请求调入页面的操作,而不是执行进程的指令,这就会大大降低系统效率。前面讲解的页面置换算法就是是讨论这里的分配方案,尽量避免抖动现象。
另外,为了防止出现抖动现象,需要选择合适的驻留集大小。驻留集(或工作集)是指在某段时间间隔内,进程要访问的页面集合。经常被使用的页面需要在驻留集中,而长期不被使用的页面要从驻留集中被丢弃。驻留集模型使用较为简单:操作系统跟踪每个进程的驻留集,并为进程分配大于驻留集的的空间。如果还有空闲,那么可启动另一个进程。如果所有驻留集之和增加一直超过了可用物理块啊的总数,那么系统会怎听一个进程,将其页面调出并且将其物理块分配给其他进程。
正确选择驻留集的大小,对存储器的有效利用和系统吞吐量的提高,都将产生重要的影响。
6、请求分段管理方式
7、请求段页式管理方式
请求段页式管理方式只要求将作业若干页或段装入内存就可以开始运行作业,作业的其他部分别放在外存中,等待运行需要的时候才被调入内存,
请求段页式管理方式要求相对程序按逻辑意义分段后再分页,所以相对于请求页式管理方式能够方便用户使用,便于共享、保护和动态链接。进程在启动的时候采取与装入模式,则可以根据段的意义装入某些进程运行开始阶段所需要的段。
参考链接:https://wizardforcel.gitbooks.io/wangdaokaoyan-os/content/index.html
来源:CSDN
作者:iwenchaos
链接:https://blog.csdn.net/i_wen/article/details/103696156