回顾知识点:操作系统篇(一)

进程

进程是资源分配的最小单位,线程是CPU调度的最小单位.进程映像也称进程图像,是进程执行的上下文环境,包括处理机中各通用寄存器的值,进程的内存映像,打开文件的状态和进程占用资源的信息等。它由: 进程控制块(PCB)、进程执行的程序(code) / 程序、进程执行时所用的数据 / 数据集合、进程执行时使用的工作区组成。

每个进程都拥有自己独立的进程空间,如果一个进程在运行时所产生的地址在其地址空间之外,则发生地址越界,因此需要进行界地址保护,即当程序要访问某个内存单元时,由硬件检查是否允许,如果允许则执行,否则产生地址越界中断。

引起创建进程的事件:
1、用户登录
2、作业调度
3、提供服务(用户程序提出请求)
4、应用请求(基于应用进程的需求

进程之间的状态变化无非是运行、就绪、阻塞等状态的变化,当然会在PCB中有反映。进程控制块(PCB)中包含的典型元素有进程标识、处理器状态信息、进程控制信息、PCB程序控制块,是管理进程相关信息的,包含进程标识符信息,处理机状态信息,进程调度信息。

PCB一般包括:

1 程序ID(PID、进程句柄):它是唯一的,一个进程都必须对应一个PID。PID一般是整形数字

2 特征信息:一般分系统进程、用户进程、或者内核进程等

3.进程状态:运行、就绪、阻塞,表示进程现的运行情况

4.优先级:表示获得CPU控制权的优先级大小

5.通信信息:进程之间的通信关系的反映

6.现场保护区:保护阻塞的进程用

7.资源需求、分配控制信息

8.进程实体信息,指明程序路径和名称,进程数据在物理内存还是在交换分区(分页)中

9.其他信息:工作单位,工作区,文件信息等

进程同步与互斥:

进程同步也是进程之间直接的制约关系,是为完成某种任务而建立的两个或多个线程,这个线程需要在某些位置上协调他们的工作次序而等待、传递信息所产生的制约关系。进程间的直接制约关系来源于他们之间的合作。

进程互斥是进程之间的间接制约关系。当一个进程进入临界区使用临界资源时,另一个进程必须等待。只有当使用临界资源的进程退出临界区后,这个进程才会解除阻塞状态

产生死锁的四个必要条件
(1) 互斥条件:一个资源每次只能被一个进程使用。

(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。

(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系

解决死锁
一般地,解决死锁的方法分为死锁的预防,避免,检测与恢复三种(注意:死锁的检测与恢复是一个方法)

死锁的预防是保证系统不进入死锁状态的一种策略。它的基本思想是要求进程申请资源时遵循某种协议,从而打破产生死锁的四个必要条件中的一个或几个,保证系统不会进入死锁状态。

死锁的避免,它不限制进程有关申请资源的命令,而是对进程所发出的每一个申请资源命令加以动态地检查,并根据检查结果决定是否进行资源分配。就是说,在资源分配过程中若预测有发生死锁的可能性,则加以避免。这种方法的关键是确定资源分配的安全性。

死锁的检测与恢复

一般来说,由于操作系统有并发,共享以及随机性等特点,通过预防和避免的手段达到排除死锁的目的是很困难的。这需要较大的系统开销,而且不能充分利用资源。为此,一种简便的方法是系统为进程分配资源时,不采取任何限制性措施,但是提供了检测和解脱死锁的手段:能发现死锁并从死锁状态中恢复出来。因此,在实际的操作系统中往往采用死锁的检测与恢复方法来排除死锁。 死锁检测与恢复是指系统设有专门的机构,当死锁发生时,该机构能够检测到死锁发生的位置和原因,并能通过外力破坏死锁发生的必要条件,从而使得并发进程从死锁状态中恢复出来。

引起挂起状态的原因:

终端用户的请求。当终端用户在自己的程序运行期间发现有可疑问题时,希望暂停使自己的程序静止下来,使正在执行的进程暂停执行;若此时用户进程正处于就绪状态而未执行,则该进程暂不接受调度,以便用户研究其执行情况或对程序进行修改

父进程的请求。有时父进程希望挂起自己的某个子进程,以便考察和修改子进程,或者协调各子进程间的活动。

负荷调节的需要。当实时系统中的工作负荷较重,已可能影响到对实时任务的控制时,可由系统把一些不重要的进程挂起,以保证系统能正常运行。

操作系统的需要。操作系统有时希望挂起某些进程,以便检查运行中的资源使用情况或进行记账。对换的需要。为了缓和内存紧张的情况,将内存中处于阻塞状态的进程换至外存上。

进程状态的改变

高优先级的抢占CPU,使得原来处于运行状态的进程转变为就绪状态。
阻塞的进程等待某件事情的发生,一旦发生则它的运行条件已经满足,从阻塞进入就绪状态。
时间片轮转使得每个进程都有一小片时间来获得CPU运行,当时间片到时从运行状态变为就绪状态。
自旋锁(spinlock)是一种保护临界区最常见的技术。在同一时刻只能有一个进程获得自旋锁,其他企图获得自旋锁的任何进程将一直进行尝试(即自旋,不断地测试变量),除此以外不能做任何事情。因此没有获得自旋锁的进程在获取锁之前处于忙等(阻塞状态)。

进程,作业调度算法

作业调度,也称为高级调度,是指按一定的规则从外存上处于后备状态的作业队列挑选一个(或多个)作业,给它们分配内存、输入/输出设备等必要的资源,并建立相应的进程,使它们获得竞争处理机的权利。

FCFS(先来先服务,队列实现,非抢占的):先请求CPU的进程先分配到CPU。按照进程进入就绪队列的先后次序来选择。即每当进入进程调度,总是把就绪队列的队首进程投入运行。

SJF(最短作业优先调度算法):平均等待时间最短,但难以知道下一个CPU区间长度 优先级调度算法(可以是抢占的,也可以是非抢占的):优先级越高的越先分配到CPU, 相同优先级先到先服务,存在的主要问题是:低优先级进程无穷等待CPU, 会导致无穷阻塞式饥饿,解决方案:老化(随着时间的推移, 那些越老的进程优先级反而越高)

时间片轮转调度算法(可抢占的):队列中没有进程被分配超过一个时间片的CPU时间, 除非它是唯一可运行的进程。 如果进程的CPU区间超过了一个时间片, 那么该进程就被抢占并放回就绪队列。时间片轮转算法分配的是处理机资源,在不考虑线程的系统中,进程是获取资源并被独立调度的最小单位。时间片轮转调度算法只适用于进程调度,而不适用于作业调度。

时间片即CPU分配给各个程序的时间,每个线程被分配一个时间段,称作它的时间片,即该进程允许运行的时间,使各个程序从表面上看是同时进行的。如果在时间片结束时进程还在运行,则CPU将被剥夺并分配给另一个进程。如果进程在时间片结束前阻塞或结束,则CPU当即进行切换。而不会造成CPU资源浪费。在宏观上:我们可以同时打开多个应用程序,每个程序并行不悖,同时运行。但在微观上:由于只有一个CPU,一次只能处理程序要求的一部分,如何处理公平,一种方法就是引入时间片,每个程序轮流执行。

多级队列调度算法:将就绪队列分成多个独立的队列,每个队列都有自己的调度算法, 队列之间采用固定优先级抢占调度,其中,一个进程根据自身属性被永久地分配到一个队列中

多级反馈队列调度算法:与多级队列调度算法相比,其允许进程在队列之间移动, 若进程使用过多CPU时间,那么它会被转移到更低的优先级队列,在较低优先级队列等待时间过长的进程会被转移到更高优先级队列,以防止饥饿发生。多级队列反馈法:几种调度算法的结合形式多级队列方式。

高响应比优先算法是一种综合考虑任务长度和等待时间的调度算法,响应比=(等待时间+执行时间)/执行时间。高响应比优先算法在等待时间相同的情况下,作业执行时间越短则响应比越高,满足短任务优先。随着长任务的等待时间增加,响应比也会变大,执行机会也就增大,所以不会发生饥饿现象。先来先服务和时间片轮转不符合短任务优先,非抢占式短任务优先会产生饥饿现象。

最高优先级算法(HPF):进程调度每次将处理机分配给具有最高优先级的就绪进程。最高优先级算法可与不同的CPU方式结合形成可抢占式最高优先级算法和不可抢占式最高优先级算法。

动态优先权是指在创建进程时所赋予的优先权,是可以随进程的推进或随其等待时间的增加而改变的,以便获得更好的调度性能。例如,我们可以规定,在就绪队列中的进程,随其等待时间的增长,其优先权以速率a提高。若所有的进程都具有相同的优先权初值,则显然是最先进入就绪队列的进程将因其动态优先权变得最高而优先获得处理机,此即FCFS算法。

静态优先及调度、非抢占式作业优先、抢占式短作业优先:这三个具有优先级的,可以提高系统的效率,但并不是公平的,有可能一直被抢占发生饥饿甚至饿。

只有时间片转移是公平的,大家轮流执行,不会饿着

共享资源

每个进程中访问临界资源的那段程序称为临界区(临界资源是一次仅允许一个进程使用的共享资源)。每次只准许一个进程进入临界区,进入后不允许其他进程进入

顺序执行的特性有如下三点。 (1)顺序性:程序顺序执行时,其执行过程可看做一系列严格按程序规定的状态转移的过程,也就是每执行一条指令,系统将从上一个执行状态转移到下一个执行状态,且上一条指令的执行结束是下一条指令执行开始的充分必要条件。

(2)封闭性:程序执行得到的最终结果由给定的初始条件决定,不受外界因素的影响。

(3)无关性(可再现性):顺序执行的最终结果可再现是指运行结果与执行速度无关。只要输人的初始条件相同,则无论何时重复执行该程序都会得到相同的结果。

各种事件概念
周转时间:是指,从一个批处理作业提交时刻开始直到该作业完成时刻为止的统计的平均时间

响应时间:是指:作业等待时间+作业计算时间

运行时间:作业计算时间

程序与进程的概念:
一个程序至少有一个进程,不对。程序放在硬盘里没有执行,不会有对应的进程。

程序(program)只能有一个进程,一个进程就是一个程序。有人说,我打开一个程序,比如chrome,有十多个进程呢,这是咋回事。那就是十多个程序,操作系统给他们分配了彼此独立的内存,相互执行不受彼此约束,分配同样时间的CPU。对于用户而言,他们是一个整体,我们通常称之为应用程序(application)。对于计算机而言,一个进程就是一个程序,多个进程(比如一个浏览器的多个进程)对计算机而言就是多个不同的程序,它不会把它们理解为一个完整的“程序”。

线程
1.线程作为调度和分配的基本单位,进程作为拥有资源的基本单位

2.不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行

3.进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于

进程的资源.

4.在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销

明显大于创建或撤消线程时的开销。

在UNIX系统中进程由以下三部分组成:①进程控制块PCB;②数据段;③正文段。

UNIX系统为了节省进程控制块所占的内存空间,把每个进程控制块分成两部分。一部分常驻内存,不管进程是否正占有处理器运行,系统经常会对这部分内容进行查询和处理,常驻部分内容包括:进程状态、优先数、过程特征、数据段始址、等待原因和队列指针等,这是进行处理器调度时必须使用的一些主要信息。另一部分非常驻内存,当进程不占有处理器时,系统不会对这部分内容进行查询和处理,因此这部分内容可以存放在磁盘的对换区中,它随用户的程序和数据部分换进或换出内存。

UNIX系统把进程的数据段又划分成三部分:用户栈区(供用户程序使用的信息区);用户数据区(包括用户工作数据和非可重入的程序段);系统数据区(包括系统变量和对换信息)。

正文段是可重入的程序,能被若干进程共享。为了管理可共享的正文段,UNIX设置了一张正文表,每个正文段都占用一个表目,用来指出该正文段在内存和磁盘上的位置、段的大小以及调用该段的进程数等情况。

什么叫做程序的可重入性?
若一个 程序或 子程序可以安全的被并行执行,则称其为可重入;即当该子程序正在运行时,可以再次进入并执行它。若一个函数是可重入的,则该函数不能含有 静态(全局)非常量数据。 不能返回静态(全局)非常量数据的地址。只能处理由调用者提供的数据。 不能依赖于单实例模式资源的锁。 不能调用不可重入的函数。 多’用户/对象/进程 优先级’以及 多进程一般会使得对可重入代码的控制变得复杂。同时,IO代码通常不是可重入的,因为他们依赖于像磁盘这样共享的、单独的资源。

静态重定位和动态重定位

对程序进行重定位的技术按重定位的时机可分为两种:静态重定位和动态重定位。

静态重定位:即在程序装入内存的过程中完成,是指在程序开始运行前,程序中的各个地址有关的项均已完成重定位,地址变换通常是在装入时一次完成的,以后不再改变。

静态重定位:是在目标程序装入内存时,由装入程序对目标程序中的指令和数据的地址进行修改,即把程序的逻辑地址都改成实际的地址。对每个程序来说,这种地址变换只是在装入时一次完成,在程序运行期间不再进行重定位。 优点:是无需增加硬件地址转换机构,便于实现程序的静态连接。在早期计算机系统中大多采用这种方案。 缺点:(1)程序的存储空间只能是连续的一片区域,而且在重定位之后就不能再移动。这不利于内存空间的有效使用。(2)各个用户进程很难共享内存中的同一程序的副本。 动态重定位:是在程序执行期间每次访问内存之前进行重定位。这种变换是靠硬件地址变换机构实现的。通常采用一个重定位寄存器,其中放有当前正在执行的程序在内存空间中的起始地址,而地址空间中的代码在装入过程中不发生变化。 优点:(1)程序占用的内存空间动态可变,不必连续存放在一处。(2)比较容易实现几个进程对同一程序副本的共享使用。 缺点:是需要附加的硬件支持,增加了机器成本,而且实现存储管理的软件算法比较复杂。 现在一般计算机系统中都采用动态重定位方法

动态重定位即在程序运行过程中要访问数据时再进行逻辑地址与物理地址的变换(即在逐条指令执行时完成地址映射。

不同的存储方式:
(1)页式存储,你直接给一个逻辑地址就行,所以是一维的。虽然这个逻辑地址包含(页号,偏移量),但是,分页那是系统自己完成的事,我们不知道也不用关心最终地址到底在哪个页上。
(2)段式存储,你必须给出(段号,偏移量),所以是二维的。因为分段的好处就是程序模块化,不同的段权限不同,所以在哪个段上,是我们关心的。

按动态静态的内存分配

动态内存分配是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不象数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需要即时分配,且分配的大小就是程序要求的大小。

内存的静态分配和动态分配的区别主要是两个: 一是时间不同。静态分配发生在程序编译和连接的时候。动态分配则发生在程序调入和执行的时候。 二是空间不同。堆都是动态分配的,没有静态分配的堆

按区域的内存分配方式有三种:

(1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。

(2)在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

(3) 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多

动态链接及静态链接

静态链接就是在编译链接时直接将需要的执行代码拷贝到调用处,优点就是在程序发布的时候就不需要的依赖库,也就是不再需要带着库一块发布,程序可以独立执行,但是体积可能会相对大一些。

动态链接就是在编译的时候不直接拷贝可执行代码,而是通过记录一系列符号和参数,在程序运行或加载时将这些信息传递给操作系统,操作系统负责将需要的动态库加载到内存中,然后程序在运行到指定的代码时,去共享执行内存中已经加载的动态库可执行代码,最终达到运行时连接的目的。优点是多个程序可以共享同一段代码,而不需要在磁盘上存储多个拷贝,缺点是由于是运行时加载,可能会影响程序的前期执行性能。

动态链接库的两种链接方法:

(1)装载时动态链接(Load-time Dynamic Linking):这种用法的前提是在编译之前已经明确知道要调用DLL中的哪几个函数,编译时在目标文件中只保留必要的链接信息,而不含DLL函数的代码;当程序执行时,调用函数的时候利用链接信息加载DLL函数代码并在内存中将其链接入调用程序的执行空间中(全部函数加载进内存),其主要目的是便于代码共享。(动态加载程序,处在加载阶段,主要为了共享代码,共享代码内存)

(2)运行时动态链接(Run-time Dynamic Linking):这种方式是指在编译之前并不知道将会调用哪些DLL函数,完全是在运行过程中根据需要决定应调用哪个函数,将其加载到内存中(只加载调用的函数进内存),并标识内存地址,其他程序也可以使用该程序,并用LoadLibrary和GetProcAddress动态获得DLL函数的入口地址。(dll在内存中只存在一份,处在运行阶段)

你可能感兴趣的:(操作系统与计算机组成原理)