操作系统概念梳理

分时操作系统

分时操作系统的核心原理在于将作业直接放入内存,并引入了时间片的概念,采用轮转运行的方式,规定每个作业每次只能运行一个时间片,然后就暂停该作业并立即调度下一个作业运行。在不长的时间内使所有的作业都执行一个时间片的时间,便可以使每个用户都能及时地与自己的作业进行交互,从而使用户的请求得到及时响应。这样就解决了在分时系统中最重要的及时接收、及时处理问题。

时间片切换时通过时钟中断发起中断请求

用户态和内核态

  • 内核态:控制计算机的硬件资源,并提供上层应用程序运行的环境。
  • 用户态:上层应用程序的活动空间,应用程序的执行必须依托于内核提供的资源。

在多道程序设计环境中,从资源管理和控制程序执行的角度出发,必须把指令系统中的指令分作两类:特权指令(Privileged Instructions)和非特权指令。所谓特权指令是指那些只能提供给操作系统的核心程序使用的指令,如启动输入输出设 备、设置时钟、控制中断屏蔽位、清内存、建立存储键,加载 PSW 等。只有操作系统 才能执行全部指令(特权指令和非特权指令),如果一般用户执行特权指令,会导致 非法执行而产生保护中断。

用户态切换为内核态的三种情况:

  • 系统调用:为了使上层应用能够访问到这些资源,内核为上层应用提供访问的接口。
  • 异常事件: 当CPU正在执行运行在用户态的程序时,突然发生某些预先不可知的异常事件,这个时候就会触发从当前用户态执行的进程转向内核态执行相关的异常事件,典型的如缺页异常
  • 外围设备的中断:当外围设备完成用户的请求操作后,会向CPU发出中断信号,此时,CPU就会暂停执行下一条即将要执行的指令,转而去执行中断信号对应的处理程序,如果先前执行的指令是在用户态下,则自然就发生从用户态到内核态的转换。

中断

中断 (interrupt)是指程序执行过程中,当发生某个事件时,中止 CPU 上现行程序的运行, 引出处理该事件的服务程序执行的过程。

引起中断的事件称为中断源,不同硬件结构的中断源各不相同,从中断事件的性质来说,可以分成强迫性中断事件和自愿性中断事件两大类。 

强迫性中断事件不是正在运行的程序所期待的,而是由于某种事故或外部请求信 息所引起的。这类中断事件大致有以下几种:

  • 机器故障中断事件。例如,电源故障,主存储器出错等。
  • 程序性中断事件。例如,定点溢出,除数为 0,地址越界等。
  • 外部中断事件。例如,时钟的定时中断,控制台发控制信息等。 输入输出中断事件。例如,设备出错,传输结束等。

自愿性中断事件是正在运行的程序所期待的事件。这种事件是由于执行了一条访 管指令而引起的,它表示正在运行的程序对操作系统有某种需求,一旦机器执行到一 条访管指令时,便自愿停止现行程序而转入访管中断处理程序处理。例如,要求操作 系统协助启动外围设备工作。

发现中断源并产生中断的硬件称中断装置。迄今为止,所有的计算机系统都采用硬件和软件结合的方法实现中断处理。一般说,中断装置主要做以下三件事:

  •  发现中断源,提出中断请求。当发现多个中断源时,它将根据规定的优先级, 先后发出中断请求。

  •  保护现场。将处理器中某些寄存器内的信息存放于内存储器,使得中断处理程序运行时,不会破坏被中断程序的有用信息,以便在中断处理结束后能够返回被中断程序继续运行。

  •  启动处理中断事件的中断处理程序。
  • 中断处理结束后恢复现场,并继续执行进程调度。

进程

进程的内存映像

操作系统中把进程物理实体和支持进程运行的环境合称为进程上下 文(process context)。当系统调度新进程占有处理器时,新老进程随之发生上下文切 换,因此,进程的运行被认为是在进程的上下文中执行的。在操作系统中,进程上下 文包括三个组成部分:

  •  用户级上下文(user -level context):由用户进程的程序块、用户数据块(含 共享数据块)和用户堆栈组成的进程地址空间。

  •  系统级上下文(system -level context):包括进程的标识信息、现场信息和控 制信息,进程环境块,以及系统堆栈等组成的进程地址空间。

  •  寄存器上下文(register context):由程序状态字寄存器、各类控制寄存器、 地址寄存器、通用寄存器、用户栈指针等组成。

进程队列及其管理

PCB:进程控制块是操作系统用于记录和刻画进程状态及有关信息的数据结构,也是操作系统掌 握进程的唯一资料结构,是操作系统控制和管理进程的主要依据。它包括了进程执行 时的情况,以及进程让出处理器后所处的状态、断点等信息。

并发系统中同时存在许多进程,有的处于就绪态,有的处于等待态,等待原因各 不相同。进程的主要特征是由 PCB 来刻画的,为了便于管理和调度,常常把各个进程 的 PCB 用某种方法组织起来。用得较多的是用队列来组织 PCB,下面先介绍这种方法。

一般说来,把处于同一状态(例如就绪态)的所有进程控制块链接在一起的数据 结构称为进程队列(process queues),简称队列。同一状态进程的 PCB 既可按先来先 到的原则排成队列;也可以按优先数或其他原则排成队列。对于等待态的进程队列可 以进一步细分,每一个进程按等待的原因进入相应的等待队列,例如,如果一个进程 要求使用某个设备,而该设备已经被占用时,此进程就链接到与该设备相关的等待态 队列中去。

当发生的某个事件使一个进程的状态发生变化时,这个进程就要退出所在的某个 队列而排入到另一个队列中去。一个进程从一个所在的队列中退出的事件称为出队, 相反,一个进程排入到一个指定的队列中的事件称为入队。处理器调度中负责入队和 出队工作的功能模块称为队列管理模块,简称队列管理。

进程切换与模式切换

中断是激活操作系统的唯一方法,它暂时中止当前运行进程的执行,把处理器切 换到操作系统的控制之下。而当操作系统获得了处理器的控制权之后,它就可以实现 进程切换,所以,进程切换必定在核心态而不是在用户态下发生。当发生中断事件, 或进程执行系统调用后,有可能引发内核进行进程上下文切换,由于一个进程让出处 理器时,其寄存器上下文将被保存到系统级上下文的相应的现场信息位置,这时内核 就把这些信息压入系统栈的一个上下文层。当内核处理中断返回,或一个进程完成其 系统调用返回用户态,或内核进行上下文切换时,内核就从系统栈弹出一个上下文层 (context layer)。因此,上下文的切换总会引起上下文的压入和弹出堆栈。内核在四 种情况下允许发生上下文切换:

(1) 当进程进入等待态时;
(2) 当进程完成其系统调用返回用户态但不是最有资格获得 CPU 时;
(3) 当内核完成中断处理,进程返回用户态但不是最有资格获得 CPU 时;
(4) 当进程执行结束时。 做一次进程上下文切换时,即保存老进程的状态而装入被保护了的新进程的状态,

以便新进程运行。进程切换的步骤如下:

  • 保存被中断进程的处理器现场信息。
  • 修改被中断进程的进程控制块的有关信息,如进程状态等。
  • 把被中断进程的进程控制块加入有关队列。
  • 选择下一个占有处理器运行的进程。
  • 修改被选中进程的进程控制块的有关信息。
  • 根据被选中进程设置操作系统用到的地址转换和存储保护信息。
  • 根据被选中进程的信息来恢复处理器现场。

从上面介绍的切换工作可以看出,当进行上下文切换时,内核需要保存足够的信 息,以便将来适当时机能够切换回原进程,并恢复它继续执行。类似地,当从用户态 转到核心态时,内核保留足够信息以便后来能返回到用户态,并让进程从它的断点继 续执行。用户态到核心态或者核心态到用户态的转变是 CPU 模式的改变,而不是进程 上下文切换。为了进一步说明进程的上下文切换,下面来讨论模式切换。当中断发生 的时候,暂时中断正在执行的用户进程,把进程从用户状态切换到内核状态,去执行 操作系统例行程序以获得服务,这就是一次模式切换,注意,此时仍在该进程的上下 文中执行,仅仅模式变了。内核在被中断了的进程的上下文中对这个中断事件作处理, 即使该中断事件可能不是此进程引起的。另一点要注意的是被中断的进程可以是正在 用户态下执行的,也可以是正在核心态下执行的,内核都要保留足够信息以便在后来 能恢复被中断了的进程执行。内核在核心态下对中断事件进行处理时,决不会再产生 或调度一个特殊进程来处理中断事件。模式切换的步骤如下:

  • 保存被中断进程的处理器现场信息。
  • 根据中断号置程序计数器。
  • 把用户状态切换到内核状态,以便执行中断处理程序。

注意模式切换不同于进程切换,它并不引起进程状态的变化,在大多数操作系统 中,它也不一定引起进程的切换,在完成了中断调用之后,完全可以再通过一次逆向 的模式切换来继续执行用户进程。

显然,有效合理地使用模式切换和进程切换有利于操作系统效率和安全性的提高。 为此,大多数现代操作系统存在两种进程:系统进程和用户进程。它们并不是指两个 具体的进程实体,而是指一个进程的两个侧面,系统进程是在核心态下执行操作系统 代码的进程,用户进程在用户态下执行用户程序的进程。用户进程因中断或系统调用 进入内核态,系统进程就开始执行,这两个进程(用户进程和系统进程)使用同一个 PCB,所以,实质上是一个进程实体。但是这两个进程所执行的程序不同,映射到不 同物理地址空间、使用不同堆栈。一个系统进程的地址空间中包含所有的系统核心程 序和各进程的进程数据区,所以,各进程的系统进程除数据区不同外,其余部分全相 同,但各进程的用户进程部分则各不相同。

线程

线程是操作系统进程中能够独立执行的实体(控制流),是处理器调度和分派的基本单位。线程是进程的组成部分,每个进程内允许包含多个并发执行的实体(控制 流),这就是多线程。同一个进程中的所有线程共享进程获得的主存空间和资源,但 不拥有资源。

进程可以划分为两个部分:资源集合和线程集合。进程要支撑线 程运行,为线程提供地址空间和各种资源,它封装了管理信息,包括对指令代码、全 局数据和 I/O 状态数据等共享部分的管理。线程封装了执行信息,包括对 CPU 寄存器、 执行栈(用户栈、内核栈)和局部变量、过程调用参数、返回值等线程私有部分的管 理。由于线程具有许多传统进程所具有的特征,所以,也把线程称为轻量进程 LWP(Light-Weight Process)。

内核级线程

在纯内核级 KLT(Kernel Level Threads)线程设施中,线程管理的所有工作由操作系统内核来做。内核专门提供了一个 KLT 应用程序设计接口(API),供开发者使 用,应用程序区不需要有线程管理的代码。Windows 2000/XP 和 OS/2 都是采用这种方 法的例子。

任何应用都可以被程序设计成多个线程,当提交给操作系统执行时,内核为它创 建一个进程和一个线程,线程在执行中可以通过内核创建线程原语来创建其他线程, 这个应用的所有线程均在一个进程中获得支持。内核要为整个进程及进程中的单个线 程维护现场信息,所以,应在内核空间中建立和维护进程控制块 PCB 及线程控制块 TCB,内核的调度是在线程的基础上进行的。

这一方法有二个主要优点,首先,在多处理器上,内核能够同时调度同一进程中 多个线程并行执行;其次,若进程中的一个线程被阻塞了,内核能调度同一进程的其 他线程占有处理器运行,也可以运行其他进程中的线程。最后,由于内核线程仅有很 小的数据结构和堆栈,KLT 的切换比较快,内核自身也可以用多线程技术实现,从而, 能提高系统的执行速度和效率。

KLT 的主要缺点是:应用程序线程在用户态运行,而线程调度和管理在内核实现, 在同一进程中,控制权从一个线程传送到另一个线程时需要用户态-内核态-用户态的模 式切换,系统开销较大。

用户级线程

纯用户级线程 ULT(User Level Threads)设施中,线程管理的全部工作都由应用 程序来做,在用户空间内实现,内核是不知道线程的存在的。用户级多线程由用户空 间运行的线程库来实现,任何应用程序均需通过线程库进行程序设计,再与线程库连 接后运行来实现多线程。线程库是一个 ULT 管理的例行程序包,在这种情况下,线程 库是线程的运行支撑环境。

当一个应用程序提交给系统后,系统为它建立一个由内核管理的进程,该进程在 线程库环境下开始运行时,只有一个由线程库为进程建立的线程。首先,运行这个线 程,当应用进程处于运行状态时,线程通过调用线程库中的“孵化”过程,可以孵化 出运行在同一进程中的新线程,步骤如下:通过过程调用把控制权传送给“孵化”过 程,由线程库为新线程创建一个 TCB 数据结构,并置为就绪态,然后,按一定的调度 算法把控制权传递给该进程中处于就绪态的一个线程。当控制权传送到线程库时,当前线程的现场信息应被保存,而当线程库调度一个线程执行时,便要恢复它的现场信 息。现场信息主要包括:用户寄存器内容、程序指令计数器和堆栈指针。当线程运行, 执行系统调用,导致它挂起并进入等待态时,线程库代码会寻找一个就绪态线程来执 行,这时将进行线程上下文切换,而新线程被激活。上述活动均发生在用户空间,且在单个进程中,内核并不知道这些活动。内核按 进程为单位调度,并赋予一个进程状态(就绪、运行、阻塞...)。

下面的例子清楚地 表明了线程调度和进程调度之间的关系。假设进程 B 正在执行它的线程 2,则可能出 现下列情况:

  •  正在执行的进程 B 的线程 2 发出了一个封锁进程 B 的系统调用,例如,做了 一个 I/O 操作。这导致控制转移到内核,内核启动 I/O 操作,把进程 B 被置为 阻塞状态,并切换到另一个进程。按照由线程库所维护的数据结构,进程 B 的线程 2 仍然处在运行态。十分重要的是线程 2 的运行并不是真正意义上的 被处理器执行,而是可理解为在线程库的运行态中。这时,进程 B 中的其他 线程尽管有的处于可运行的就绪态,但因进程 B 被阻塞而也都被阻塞了。

  •  一个时钟中断传送控制给内核,内核中止当前时间片用完的进程 B,并把它 放入就绪队列,切换到另一个就绪进程,此时,由于进程 B 中线程 2 正在运 行,按由线程库维护的数据结构,进程 B 的线程 2 仍处于运行态,进程 B 却 己处于就绪态。

  •  线程 2 执行到某处,它需要进程 B 的线程 1 的某些操作。于是让线程 2 变成 阻塞态,而线程 1 从就绪态转为运行态,注意进程始终处在运行态。

    上述头两种情况中,当内核切换控制权返回到进程 B 时,便恢复原来断点现场, 线程 2 继续执行。注意到当正在执行线程库中的代码时,一个进程也有可能由于时间 片用完或被更高优先级的进程剥夺而被中断。当中断发生时,一个进程可能正处在从 一个线程切换到另一个线程的过程中间;当一个进程恢复时,继续在线程库中执行, 完成线程切换,并传送控制权给进程中的一个新线程。使用 ULT 代替 KLT 有许多优 点:

  •  线程切换不需要内核特权方式,因为,所有线程管理数据结构均在单个进程 的用户空间中,管理线程切换的线程库也在用户地址空间运行,因而,进程 不要切换到内核方式来做线程管理。这就节省了模式切换的开销,也节省了 内核的宝贵资源。

  •  按应用特定需要允许进程选择调度算法,一种应用可能从简单轮转调度算法 得益,同时,另一种应用可能从优先级调度算法获得好处。在不干扰操作系 统调度的情况下,根据应用需要可以裁剪调度算法,也就是说,线程库的线 程调度算法与操作系统的低级调度算法是无关的。

    ULT 能运行在任何操作系统上,内核在支持 ULT 方面不需要做任何改变。线程库 是可以被所有应用共享的应用级实用程序,许多当代操作系统和语言均提供了线程库, 传统 UNIX 并不支持多线程,但已有了多个基于 UNIX 的用户线程库。

    和 KLT 比较,ULT 有二个明显的缺点:

    •  在传统的基于进程操作系统中,大多数系统调用将阻塞进程,因此,当线程执行一个系统调用时,不仅该线程被阻塞,而且,进程内的所有线程会被阻塞。而在 KLT 中,这时可以去选择另一个线程运行。

    •  在纯 ULT 中,多线程应用不能利用多重处理的优点。内核在一段时间里,分配一个进程仅占用一个 CPU,因而,进程中仅有一个线程能执行。因此,尽 管多道程序设计能够明显地加快应用处理速度,也具备了在一个进程中进行 多线程设计的能力,但通常不可能得益于多线程并发地执行。

存储

分页式存储管理

用分区方式管理的存储器,每道程序总是要求占用主存的一个或几个连续存储区 域,主存中会产生许多碎片,因此,有时为了接纳一个新的作业而往往要移动已在主 存的信息,这不仅不方便,而且开销不小。采用分页式存储器允许把一个作业存放到 若干不相邻接的分区中,既可免去移动信息的工作,又可充分利用主存空间,尽量减 少主存内的碎片。分页式存储管理的基本原理如下:

1、页框:物理地址分成大小相等的许多区,每个区称为一块(又称页框 page frame);

2、页面:逻辑地址分成大小相等的区,区的大小与块的大小相等,每个区称一个 页面(page)。

3、逻辑地址形式:与此对应,分页存储器的逻辑地址由两部分组成:页号和单元号。

采用分页式存储管理时,逻辑地址是连续的。所以,用户在编制程序时仍只须使用顺序的地址,而不必考虑如何去分页。由地址转换机构和操作系统管理的需要来决定页面的大小, 从而,也就确定了主存分块的大小。用户进程在主存空间中的每个页框内的地址是连续的, 但页框和页框之间的地址可以不连续。存储地址由连续到离散的变化,为以后实现程序的 “部分装入、部分对换”奠定了基础。

4、页表和地址转换:在进行存储分配时,总是以块(页框)为单位的,一个作业 的信息有多少页,那么,在把它装入主存时就给它分配多少块。但是,分配给作业的 主存块可以不连续,即作业的信息可按页分散存放在主存的空闲块中,这就避免了为 得到连续存储空间而进行的移动。那么,当作业的程序和数据被分散存放后,作业的 页面与分给的页框如何建立联系呢?逻辑地址(页面)如何变换成物理地址(页框)呢? 作业的物理地址空间由连续变成分散后,如何保证程序正确执行呢?采用的办法仍然 是动态重定位技术,让程序的指令执行时动态地进行地址变换,由于程序以页面为单 位,所以,给每个页面设立一个重定位寄存器,这些重定位寄存器的集合便称页表(page table)。页表是操作系统为每个用户作业建立的,用来记录程序页面和主存对应页框 的对照表,页表中的每一栏指明了程序中的一个页面和分得的页框的对应关系。所以, 页表的目的是把页面映射为页框,从数学的角度来说,页表是一个函数,它的变量是 页面号,函数值为页框号,通过这个函数可把逻辑地址中的逻辑页面域替换成物理页 框域。通常为了减少开销,不是用硬件,而是在主存中开辟存储区存放页表,系统中 另设一个页表主存起址和长度控制寄存器(page table control register),存放当前运行 作业的页表起址和页表长,以加快地址转换速度。每当选中作业运行时,应进行存储 分配,为进入主存的每个用户作业建立一张页表,指出逻辑地址中页号与主存中块号 的对应关系,页表的长度随作业的大小而定。同时分页式存储管理系统还建立一张作 业表,将这些作业的页表地址进行登记,每个作业在作业表中有一个登记项。然后,借助于硬件的地址转换机构,在作业执行过程中 按页面动态重定位。调度程序在选择作业后,从作业表的登记项中得到被选中作业的 页表始址和长度,将其送入硬件设置的页表控制寄存器。地址转换时,只要从页表控制寄存器就可以找到相应的页表,再按照逻辑地址中的页号作索引查页表,得到对应 的块号,根据关系式:绝对地址 = 块号×块长 + 单元号,计算出欲访问的主存单元的地址。因此,虽然作业存放在若干个不连续的块中,但在作业执行中总是能按正确的地址进行存取。

整个系统只有一个页表控制寄存器,只有占用 CPU 的作业才占有页表控制寄存器。 在多道程序中,当某道程序让出处理器时,应同时让出页表控制寄存器。

虚拟存储管理

在各种存储管理方式中,必须为作业分配足够的存储空间,以装入有 关作业的全部信息,当然作业的大小不能超出主存的可用空间,否则,这个作业是无 法运行的。但当把有关作业的全部信息都装入主存储器后,作业执行时实际上不是同 时使用全部信息的,有些部分运行一遍便再也不用,甚至有些部分在作业执行的整个 过程中都不会被使用(如错误处理部分)。作业在运行时不用的,或暂时不用的,或 某种条件下才用的程序和数据,全部驻留于主存中是对宝贵的主存资源的一种浪费, 大大降低了主存利用率。于是,提出了这样的问题:作业提交时,先全部进入辅助存 储器,作业投入运行时,能否不把作业的全部信息同时装入主存储器,而是将其中当 前使用部分先装入主存储器,其余暂时不用的部分先存放在作为主存扩充的辅助存储 器中,待用到这些信息时,再由系统自动把它们装入到主存储器中,这就是虚拟存储 器的基本思路。当一个进程访问的程序和数据在主存中,执行就可以顺利进行。如果 处理器访问了不在主存的程序或数据,为了继续执行下去,需要由系统自动将这部分 信息装入主存储器,这叫部分装入;如若主存中没有足够空闲空间,便需要把主存中 暂时不用的信息从主存移到辅存上去,这叫部分对换。如果“部分装入、部分对换” 这个问题能解决的话,那么,当主存空间小于作业需要量时,这个作业也能执行;更 进一步,多个作业存储总量超出主存总容量时,也可以把它们全部装入主存,实现多 道程序运行。这样,不仅使主存空间能充分地被利用,而且用户编制程序时可以不必 考虑主存储器的实际容量的大小,允许用户的逻辑地址空间大于主存储器的绝对地址空间。对于用户来说,好像计算机系统具有一个容量硕大的主存储器,把它称作为“虚 拟存储器”(virtual memory)

页交换

实现虚拟存储器能给用户提供一个容量很大的存储空间,但当主存空间已装满而又要装入新页时,必须按一定的算法把已在主存的一些页面调出去,这个工作称页面替换。

替换算法常常要挑选一个页面淘汰出主存,但是这个被淘汰出去的页面可能很快又要使用,被重新装入主存。因而,操作系统必须把被淘汰的页面内容保存在磁盘的 特殊区域,例如,UNIX/Linux 使用交换区(可以是盘的一个分区称交换设备,也可以 是一个或多个文件称交换文件)临时保存页面,系统初始化时,保留一定盘空间作交 换区,初始化内容为空,不能被文件系统使用。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值