北京大学《操作系统原理》(陈向群主讲)课堂笔记(一)

北京大学《操作系统原理》(陈向群主讲)课堂笔记(一)

一、操作系统概述

1.1、操作系统做了什么?

以c语言helloworld为例子:

#include<stdio.h>
int main(int argc, char *argv[])
{
    puts("hello world");
    return 0;
}

用户告诉操作系统执行helloworld程序。

        如何告知?

                1、命令行输入相应的命令

                2、鼠标双击helloworld图标

操作系统:找到helloworld程序的相关信息,检查其类型是否是可执行文件;并通过程序首部信息确定代码和数据在可执行文件中的位置并计算对应的磁盘块地址。

        文件格式?

                1、Windows操作系统下可执行文件格式是.exe。

                2、Linux操作系统下可执行文件格式是.elf。

操作系统:创建一个新的进程,并将helloworld可执行文件映射到该进程结构,表示由该进程执行helloworld程序。

操作系统:为helloworld程序设置CPU上下文环境并跳到程序开始处(假设调度程序选中helloworld程序,会在下一个指令周期跳到程序开始处)。

执行helloworld程序的第一条指令,发生缺页异常

        为什么呢?

                因为程序在执行的时候会先把代码的程序和数据读入内存,CPU才能去执行。但是此时helloworld程序还没有把代码的程序和数据读入内存,所以此时硬件机制就会捕获出缺页异常,并且把控制权交给操作系统。

操作系统(页式存储方案):分配一页物理内存,并将代码从磁盘读入内存,然后继续执行helloworld程序。

        有的时候程序内存很大,一页物理内存不足以存储整个程序,因此在执行过程中会发生多次的缺页异常。然后到磁盘读入程序到内存,这个过程会执行多次。

helloworld程序执行puts函数(系统调用),在显示器上打印出字符串。

操作系统:找到要将字符串送往的显示设备,通常设备是由一个进程控制的,所以操作系统将要写的字符串发送给该进程。

操作系统:控制设备的进程告诉设备的窗口系统要显示字符串,窗口系统确定这是一个合法的操作,然后将字符串转换成像素,将像素写入设备的存储映像区。

视频硬件将像素转换成显示器可接收的一组控制/数据信号。

显示器解释信号,激发液晶屏。

用户可在屏幕上看到了“hello world”。

1.2、操作系统的定义与作用

操作系统是什么?

        操作系统是计算机系统中的一个系统软件,是一些程序模块的集合。

                1、它们能以尽量有效、合理的方式组织和管理计算机的软硬件资源。

                2、合理地组织计算机的工作流程,控制程序的执行并向用户提供各种服务功能。

                3、使得用户能够灵活、方便地使用计算机,使整个计算机系统高效率运行。

        解读几个关键词。

                有效:系统效率,资源利用率

                       CPU利用率充足与否?I/O设备是否忙碌?

                合理:各种软硬件资源的管理是否公平合理

                        如果不公平、不合理,则可能会产生什么问题?

                方便使用:用户界面或编程接口。

操作系统的三个作用

        资源的管理者                →        有效

                硬件资源:CPU,内存,设备(I/O设备、磁盘、时钟、网卡等)

                软件资源:磁盘上的文件、各类管理信息等

        向用户提供各种服务      →        方便使用

        对硬件机器的扩展          →        扩展能力

怎么管理资源?       

        跟踪记录资源的使用状况。

                如:哪些资源空闲,分配给谁使用,允许使用多长时间等。

        确定资源分配策略--算法

                静态资源策略

                动态资源策略

        实施资源的分配与回收。

        提高资源的利用率。

        保护资源的利用。

        协调多个进程对资源请求的冲突。

从资源管理的角度 - 五大基本功能

        进程/线程管理(CPU管理)

                进程线程状态、控制、同步互斥、通信、调度等。

        存储管理

                分配/回收、地址转换、存储保护、内存扩充等。

        文件管理

                文件目录、文件操作、磁盘空间、文件存取控制等。

        设备管理

                设备驱动、分配回收、缓存技术等。

        用户接口

                系统命令、编程接口。

OS是各种系统服务的提供者

        在操作系统之上,从用户角度来看:

                操作系统为用户提供了一组功能强大、方便易用的命令或系统调用。

        典型的服务:

                进程的创建、执行;文件和目录的操作;I/O设备的使用;各类统计信息等。

OS是硬件之上的第一层软件

        应用程序

        ------------虚拟机器界面

        操作系统

        -----------物理机器界面

        硬件

OS对硬件机器的扩展

        操作系统在应用程序与硬件之间建立了一个等价的扩展机器(虚拟机)。

        对硬件抽象,提高可移植性;比底层硬件更容易编程。

1.3、操作系统的主要特征

操作系统的特征:并发、共享、虚拟和随机

OS特征-并发

        并发:指处理多个同时性活动的能力。

                由于并发将会引起很多的问题:活动切换、保护、相互依赖的活动间的同步。

                在计算机系统中同时存在多个程序运行,单CPU--

                        宏观上:这些程序同时在执行。

                        微观上:任何时刻只有一个程序真正在执行,即这些程序在CPU上是轮流执行的。

        并行:与并发相似,但多指不同程序同时在多个硬件部件上执行。

OS特征-共享

        共享:操作系统与多个用户的程序共同使用计算机系统中的资源(共享有限的系统资源)

        操作系统要对系统资源进行合理分配和使用。

        资源在一个时间段内交替被多个进程所用。

  

        互斥共享(如打印机)

        同时共享(如可重入代码、磁盘文件)

OS特征-虚拟

        虚拟:一个物理实体映射为若干个对应的逻辑实体(分时或分空间)。

        虚拟是操作系统管理系统资源的重要手段,可提高资源利用率。

        如:

                CPU:每个进程的“虚处理机”。

                存储器:每个进程都有独立的虚拟地址空间(代码+数据+堆栈)。

                显示设备:多窗口或虚拟终端。

OS特征-随机

        随机:操作系统必须随时对以不可预测的次序发生的事件进行响应并处理。

        如:

                进程的运行速度不可预知:多个进程并发执行,“走走停停”,无法预知每个进程的运行推进的快慢。

                难以重现系统在某个时刻的状态(包括重现运行中的错误)。

1.4、典型操作系统的架构

Windows操作系统的体系结构

        抽象成四层:

应用程序
系统功能调用
操作系统
计算机硬件

UNIX架构

        抽象成四层:

UNIX命令和库
系统调用接口
内核
硬件

LINUX架构

ANDROID操作系统的整体架构

Android应用程序

Email客户端,SMS短消息程序,日历,地图,浏览器,联系人管理等

应用程序框架

开发者可以完全使用核心应用程序所使用的APIs框架视图、内容提供者、资源管理器等

系统库和Android运行时

Android包含一个C/C++库的集合,供Android系统的各个组件使用。如:系统c库、3D库、SQLite、媒体库等

Linux内核

提供核心系统服务,例如:安全、内存管理、进程管理、网络协议栈、驱动模型

1.5、操作系统的分类

操作系统的发展历程

        操作系统发展是随着计算机硬件技术、应用需求的发展、软件新技术的出现而发展的。

        目标:充分利用硬件提供更好的服务

        发展历程:大型机器→个人计算机→网络→移动计算→云计算→泛在计算(物联网)→机器人。

传统操作系统的分类

        批处理操作系统

        分时操作系统

        实时操作系统

        个人计算机操作系统

        网络操作系统

        分布式操作系统

        嵌入式操作系统

批处理操作系统

        问题:慢速的输入输出处理直接由主机来完成,输入输出时,CPU处于等待状态。

        解决方案:

                卫星机:完成面向用户的输入输出(纸带或卡片),中间结果暂存在磁带或磁盘上。

        单道批处理系统:一次只处理一个作业。

        多道批处理系统:一次处理多个作业。

        SPOOLING系统(Simultaneous Peripheral Operation On-Line,同时的外围设备联机操作,又称假脱机技术)

                批处理系统的实现通常采用的技术。

                思想:利用磁盘做缓冲,将输入、计算、输出分别组织成独立的任务流,使I/O和计算真正并行。

                工作原理:

                        用户作业加载到磁盘上的输入井。

                        按某种调度策略选择几个搭配得当的作业,调入内存。

                        作业运行的结果输出到磁盘上的输出井。

                        运行结果从磁盘上的输出井送到打印机。

                现代计算机系统的打印过程通常采用的是SPOOLing技术。

分时操作系统

        时间片:操作系统将CPU的时间划分成若干个片段,称为时间片。

                操作系统以时间片为单位,轮流为每个终端用户服务,每次服务一个时间片。

                其特点是利用人的错觉,使用户感觉不到计算机在服务他人。

                追求目标:及时响应(依据是响应时间)。

                响应时间:从终端发出命令到系统给予回答所经历的时间。

通用操作系统

        分时系统与批处理系统结合。

        原则:分时优先,批处理在后。

        “前台”:需要频繁交互的作业。

        “后台”:时间性要求不强的作业。

实时操作系统

        实时操作系统:指使计算机能及时响应外部事件的请求,在规定的严格时间内完成对该事件的处理,并控制所有实时设备和实时任务协调一致地工作。

        分类:

                第一类:实时过程控制。

                        工业控制、航空、军事控制等。

                第二类:实时通信(信息)处理。

                        电讯(自动交换机)、银行、飞机订票、股市行情。

        追求目标:

                对外部请求在严格时间范围内作出响应。

                高可靠性。

        特征:

                关键参数是时间。例子:工业过程控制系统-汽车装配线。

                硬实时系统:某个动作绝对必须在规定的时刻或时间范围完成。

                软实时系统:接受偶尔违反最终时限。

个人计算机操作系统

        计算机在某一时间内为单用户服务。

        追求目标:

                界面友好,使用方便。

                丰富的应用软件。

网络操作系统

        基于计算机网络在各种计算机操作系统上按网络体系结构协议标准开发的软件

        功能:网络管理,通信,安全,资源共享和各种网络应用。

        追求目标:相互通信,资源共享。

分布式操作系统

        分布式系统:或以计算机网络为基础,或以多处理机为基础,基本特征是处理分布在不同计算机上。

        分布式操作系统:是一个统一的操作系统,允许若干个计算机可相互协作共同完成一项任务。操作系统可将各种系统任务在分布式系统中任何处理机上运行,自动实现全系统范围内的任务分配、自动调度、均衡各处理机的工作负载。

        处理能力增强、速度更快、可靠性增强、具有透明性。

嵌入式操作系统

        嵌入式系统

                在各种设备、装置或系统中,完成特定功能的软硬件系统。如汽车、手机、电视机、MP3播放器。

                它们是一个大设备、装置或系统中的一部分,这个大设备、装置或系统可以不是“计算机”。

                通过工作在反应式或对处理时间有较严格要求环境中。

        嵌入式操作系统

                运行在嵌入式系统环境中,对整个嵌入式系统以及它所操作、控制的各种部件装置等等资源进行统一协调、调度、指挥和控制的系统软件。

二、处理器概述

2.1、处理器状态(模式)

中央处理器(CPU)

        处理器由运算器、控制器、一系列的寄存器以及高速缓存构成。

        两类寄存器:

                用户可见的寄存器:高级语言编译器通过优化算法分配并使用,以减少程序访问内存次数。

                控制和状态寄存器:用于控制处理器的操作。通常由操作系统代码使用。

控制和状态寄存器

        用于控制处理器的操作。

        在某种特权级别下可以访问、修改。

        常见的控制和状态寄存器:

                程序计数器(PC),记录将要取出的指令的地址。

                指令寄存器(IR),记录最近取出的指令。

                程序状态字(PSW),记录处理器的运行状态。如条件吗、模式、控制位等信息。

操作系统的需求-保护

        从操作系统的特征考虑:并发、共享。

        提出要求:实现保护与控制。

        需要硬件提供基本运行机制:

                处理器具有特权级别,能在不同的特权级运行的不同指令集合。

                硬件机制可将OS与用户程序隔离。

处理器的状态(模式)

        现代处理器通常将CPU状态设计划分为两种、三种或四种。

        在程序状态字寄存器PSW中专门设置一位,根据运行程序对资源和指令的使用权限而设置不同的CPU状态。

特权指令和非特权指令

        操作系统需要两种CPU状态:

                内核态:运行操作系统程序。

                用户态:运行用户程序。

        特权指令:只能由操作系统使用、用户程序不能使用的指令

                例如:启动I/O、内存清零、修改程序状态字、设置时钟、允许/禁止中断、停机。

        非特权指令:用户程序可以使用的指令

                例如:控制转移、算术运算、访管指令、取数指令。

实例:x86系列处理器

        x86支持4个处理器特权级别。

                特权环:R0、R1、R2和R3。

                        从R0到R3,特权能力由高到低。

                        R0相当于内核态;R3相当于用户态;R1和R2则介于两者之间

                        不同级别能够运行的指令集合不同。

                目前大多数基于x86处理器的操作系统,只用了R0和R3两个特权级别

CPU状态之间的转换

        用户态→内核态

                唯一途径:中断/异常/陷入机制

        内核态→用户态

                设置程序状态字PSW

一条特殊的指令:陷入指令(又称访管指令,内核态有时又称为管理态

        提供给用户程序的接口,用于调用操作系统的功能(服务)。
例如:int,trap,syscall,sysenter/sysexit。

2.2、中断与异常机制介绍(操作系统的驱动力)

中断/异常机制

        中断/异常:

                对于操作系统的重要性就好比汽车的发动机、飞机的引擎。

                可以说:操作系统是由“中断驱动”或者“事件驱动”的

        主要作用

                及时处理设备发来的中断请求。

                可使OS捕获用户程序提出的服务请求。

                防止用户程序执行过程中的破坏性活动。

                等等。

中断/异常的概念

        CPU对系统发生的某个事件作出的一种反应。

        CPU暂停正在执行的程序,保留现场后自动转去执行相应事件的处理程序,处理完成后返回断点继续执行被打断的程序。

        事件的发生改变了处理器的控制流。

        特点:
                是随机发生的。
                是自动处理的。
                是可恢复的。

为什么引入中断与异常?

        中断的引入:为了支持CPU和设备之间的并行操作。

                当CPU启动设备进行输入/输出后,设备便可以独立工作,CPU转去处理与此次输入/输出不相关的事情;当设备完成输入/输出后,通过向CPU发中断报告此次输入/输出的结果,让CPU决定如何处理以后的事情。

        异常的引入:表示CPU执行指令时本身出现的问题。

                如算术溢出、除零、取数时的奇偶错,访存地址时越界或执行了“陷入指令”等,这时硬件改变了CPU当前的执行流程,转到相应的错误处理程序或异常处理程序或执行系统调用。

事件

        中断:外部事件,正在运行的程序所不期望的。

        异常:由正在执行的指令引发。

类别原因异步/同步返回行为
中断Interrupt来自l/O设备、其他硬件部件异步总是返回到下一条指令
陷入Trap(异常)有意识安排的同步返回到下一条指令
故障Fault(异常)可恢复的错误同步返回到当前指令
终止Abort(异常)不可恢复的错误同步不会返回

2.3、中断与异常机制工作原理

中断/异常机制工作原理

        中断/异常机制是现代计算机系统的核心机制之一。

                硬件和软件相互配合而使计算机系统得以充分发挥能力。

        硬件该做什么事?        中断/异常响应

                捕获中断源发出的中断/异常请求,以一定方式响应,将处理器控制权交给特定的处理程序。

        软件要做什么事?        中断/异常处理程序

                识别中断/异常类型并完成相应的处理。

中断响应

        中断响应:发现中断、接收中断的过程,由中断硬件部件完成。

        处理器控制部件中设有中断寄存器

中断响应过程示意图:

中断向量表

        中断向量:一个内存单元,存放中断处理程序入口地址和程序运行时所需的处理机状态字

        执行流程按中断号/异常类型的不同,通过中断向量表转移控制权给中断处理程序。

        如LINUX的中断向量表:

向量范围用途
0~19不可屏蔽中断和异常
20~31Intel保留
32~127外部中断(IRQ)
128(0x80)用于系统调用的可编程异常
129~238外部中断
239本地APIC时钟中断
240本地APIC高温中断
241~250Linux保留
251~253处理器间中断
254本地APIC错误中断
255本地APIC伪中断
不可屏蔽中断/异常向量用途
0除零
1单步调试
4算术溢出
6非法操作数
12栈异常
13保护性错误
14缺页异常

中断响应流程

        1、设备发中断信号到CPU。

        2、CPU的PSW、PC寄存器(硬件)保存现场。

        3、CPU根据中断码查中断向量表。

        4、CPU把中断处理程序入口地址等推送到相应的寄存器。

        5、执行中断处理程序。

        6、恢复现场。

中断处理程序(软件提前设置好,硬件部件来执行)

        设计操作系统时,为每一类中断/异常事件编好相应的处理程序,并设置好中断向量表。

        系统运行时若响应中断,中断硬件部件将CPU控制权转给中断处理程序:

                保存相关寄存器信息。

                分析中断/异常的具体原因。

                执行对应的处理功能。

                恢复现场,返回被事件打断的程序。

以设备输入输出中断为例:

        打印机给CPU发中断信号。

        CPU处理完当前指令后检测到中断,判断出中断来源并向相关设备发确认信号。

        CPU开始为软件处理中断做准备:

                处理器状态被切换到内核态。

                在系统栈中保存被中断程序的重要上下文环境,主要是程序计数器PC、程序状态字PSW。

        CPU根据中断码查中断向量表,获得与该中断相关的处理程序的入口地址,并将PC设置成该地址,新的指令周期开始时,CPU控制转移到中断处理程序。

        中断处理程序开始工作。

                在系统栈中保存现场信息。

                检查I/0设备的状态信息,操纵I/O设备或者在设备和内存之间传送数据等等。

        中断处理结束时,CPU检测到中断返回指令,从系统栈中恢复被中断程序的上下文环境,CPU状态恢复成原来的状态,PSW和PC恢复成中断前的值,CPU开始一个新的指令周期。

举例:l/0中断处理程序

        通常分为两类处理:

                I/0操作正常结束。

                        若有程序正等待此次I/0的结果,则应将其唤醒。

                        若要继续I/0操作,需要准备好数据重新启动I/0。

                I/0操作出现错误。

                        需要重新执行失败的I/0操作。

                        重试次数有上限,达到时系统将判定硬件故障。

2.4、实例:x86的中断与异常机制

2.5、系统调用机制(操作系统向用户程序提供的接口)

系统调用:用户在编程时可以调用的操作系统功能。

        系统调用是操作系统提供给编程人员的唯一接口。

        使CPU状态从用户态陷入内核态。

每个操作系统都提供几百种系统调用(进程控制、进程通信、文件使用、目录操作、设备管理、信息维护等)。

系统调用机制的设计

        1、中断/异常机制。

                支持系统调用服务的实现。

        2、选择一条特殊指令:陷入指令(亦称访管指令)。

                引发异常,完成用户态到内核态的切换。

        3、系统调用号和参数。

                每个系统调用都事先给定一个编号(功能号)。

        4、系统调用表。

                存放系统调用服务例程的入口地址。

参数传递过程问题

        怎样实现用户程序的参数传递给内核?

                常用的3种实现方法:

                        由陷入指令自带参数:陷入指令的长度有限,目还要携带系统调用功能号,只能自带有限的参数。

                        通过通用寄存器传递参数:这些寄存器是操作系统和用户程序都能访问的,但寄存器的个数会限制传递参数的数量。

                        在内存中开辟专用堆栈区来传递参数。

系统调用的执行过程

        当CPU执行到特殊的陷入指令时:

                中断/异常机制:硬件保护现场;通过查中断向量表把控制权转给系统调用总入口程序。

                系统调用总入口程序:保存现场;将参数保存在内核堆栈里;通过查系统调用表把控制权转给相应的系统调用处理例程或内核函数。

                执行系统调用例程。

                恢复现场,返回用户程序。

2.6、实例:基于x86的Linux系统调用机制简介

三、进程/线程模型

进程模型

        多道程序设计

        进程的概念、进程控制块

        进程状态及转换、进程队列

        进程控制(进程创建、撤销、阻塞、唤醒、…)

线程模型

        为什么引入线程?

        线程的组成

        线程机制的实现(用户级线程、核心级线程、混合方式)

3.1、进程的基本概念

多道程序设计

        允许多个程序同时进入内存并运行,其目的是为了提高系统效率。

并发环境

        一段时间间隔内,单处理器上有两个或两个以上的程序同时处于开始运行但尚未结束的状态,并且次序不是事先确定的

        并发程序:在并发环境中执行的程序。

进程(任务)的定义

        定义:进程是具有独立功能的程序关于某个数据集合上的一次运行活动,是系统进行资源分配和调度的独立单位。

        程序的一次执行过程。

        是正在运行程序的抽象。

        将一个CPU变幻成多个虚拟的CPU。

        系统资源以进程为单位分配,如内存、文件、…。每个具有独立的地址空间。

        操作系统将CPU调度给需要的进程。

进程控制块PCB

        PCB:Process Control Block,进程描述符,进程属性。

                操作系统用于管理控制进程的一个专门数据结构。

                记录进程的各种属性,描述进程的动态变化过程。

        PCB是系统感知进程存在的唯一标志。

                进程与PCB是一一对应的

        进程表:所有进程的PCB集合

PCB的内容:

        进程描述信息。

        进程控制信息。

        所拥有的资源和使用情况。

        CPU现场信息。

进程描述信息

        进程标识符(process ID),唯一,通常是一个整数。

        进程名,通常基于可执行文件名,不唯一。

        用户标识符(user lD)。

        进程组关系。

进程控制信息

        当前状态。

        优先级(priority)。

        代码执行入口地址。

        程序的磁盘地址。

        运行统计信息(执行时间、页面调度)。

        进程间同步和通信。

        进程的队列指针。

        进程的消息队列指针。

所拥有的资源和使用情况

        虚拟地址空间的状况。

        打开文件列表。

CPU现场信息

        寄存器值(通用寄存器、程序计数器PC、程序状态字PSW、栈指针)

        指向该进程页表的指针。

3.2、进程状态及状态转换

进程的三种基本状态:运行态、就绪态、等待态。

        运行态(Running):占有CPU,并在CPU上运行。

        就绪态(Ready):已经具备运行条件,但由于没有空闲CPU,而暂时不能运行。

        等待态(Waiting/Blocked):因等待某一事件而暂时不能运行。

三状态模型及状态转换

        就绪 → 运行

                调度程序选择一个新的进程运行。

        运行 → 就绪

                运行进程用完了时间片。

                一个高优先级进程进入就绪状态,抢占正在运行的进程。

        运行 → 等待

                当一个进程等待某个事件发生时。

                        请求OS服务。

                        对资源的访问尚不能进行。

                        等待l/0结果。

                        等待另一进程提供信息。

                        .......

        等待→就绪

                所等待的事件发生了。

进程的其他状态

        创建new

                已完成创建一进程所必要的工作(PID、PCB)。

                但尚未同意执行该进程(因为资源有限)。

        终止Terminated

                终止执行后,进程进入该状态。

                可完成一些数据统计工作。

                资源回收。

        挂起suspend

                用于调节负载。

                进程不占用内存空间,其进程映像交换到磁盘上。

五状态进程模型

七状态进程模型

LINUX状态示意图

进程队列

        操作系统为每一类进程建立一个或多个队列。

        队列元素为PCB。

        伴随进程状态的改变,其PCB从一个队列进入另一个队列。

        多个等待队列等待的事件不同。

        就绪队列也可以多个。

        单CPU情况下,运行队列中只有一个进程。

3.3、进程控制

进程控制

        进程控制操作完成进程各状态之间的转换,由具有特定功能的原语完成。

                进程创建原语。

                进程撤消原语。

                阻塞原语。

                唤醒原语。

                挂起原语。

                激活原语。

                改变进程优先级。

                ......

        原语(primitive),又称原子操作(atomic)

                完成某种特定功能的一段程序,具有不可分割性或不可中断性

                即原语的执行必须是连续的,在执行过程中不允许被中断

进程的创建

        给新进程分配一个唯一标识以及进程控制块。

        为进程分配地址空间。

        初始化进程控制块。

                设置默认值(如: 状态为 New,..)。

        设置相应的队列指针。

                如:把新进程加到就绪队列链表中。

        UNIX:fork/exec。

        WINDOWS:CreateProcess。

进程的撤消(结束进程)

        收回进程所占有的资源。

                关闭打开的文件、断开网络连接、回收分配的内存、......

        撤消该进程的PCB。

        UNIX:exit。

        WINDOWS:TerminateProcess。

进程阻塞

        处于运行状态的进程,在其运行过程中期待某一事件发生,如等待键盘输入、等待磁盘数据传输完成、等待其它进程发送消息,当被等待的事件未发生时,由进程自己执行阻塞原语,使自己由运行态变为阻塞态。

        UNIX:wait。

        WINDOWS:WaitForSingleObject。

UNIX的几个进程控制操作(系统调用的形式)

        fork():通过复制调用进程来建立新的进程,是fork()最基本的进程建立过程。

        exec():包括一系列系统调用,它们都是通过用一段新的程序代码覆盖原来的地址空间,实现进程执行代码的转换

        wait():提供初级进程同步操作,能使一个进程等待另外一个进程的结束。

        exit():用来终止一个进程的运行。

UNIX的FORK()实现

        为子进程分配一个空闲的进程描述符。

                proc 结构

        分配给子进程唯一标识pid。

        以一次一页的方式复制父进程地址空间。(Linux采用了写时复制技术COW加快创建进程Copy-0n-Write,提高了效率,即父进程传递父进程地址空间的指针给子进程,把父进程地址空间设置为只读,当需要写入时OS单独开辟空间,把需要的内容放进去)

        从父进程处继承共享资源,如打开的文件和当前工作目录等。

        将子进程的状态设为就绪,插入到就绪队列。

        对子进程返回标识符0

        向父进程返回子进程的pid

使用FORK()的示例代码

#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>

void main(int argc, char *argv[])
{
    pid_t pid;

    pid = fork();    /* 创建一个子进程 */
    if (pid < O)     /* 出错 */
    {
        fprintf(stderr, "fork failed");
        exit(-1); 
    }else if (pid == 0)    /* 子进程 */
    {
        execlp("/bin/Ls", "Ls", NULL);
    }else                  /* 父进程 */
    {
        wait(NULL);        /* 父进程等待子进程结束 */
        printf("child complete");
        exit(0);
    }
}

3.4、关于进程相关概念的讨论

进程的分类

        系统进程

        用户进程

        前台进程

        后台进程

        CPU密集型进程

        l/0密集型进程

进程层次结构

        UNIX进程家族树:init为根

        Windows:地位相同

进程与程序的区别

        进程更能准确刻画并发,而程序不能。

        程序是静态的,进程是动态的。

        进程有生命周期的,有诞生有消亡,是短暂的;而程序是相对长久的。

        一个程序可对应多个进程。

        进程具有创建其他进程的功能。

进程映像(IMAGE)

        对进程执行活动全过程的静态描述。

                由进程地址空间内容、硬件寄存器内容及与该进程相关的内核数据结构、内核栈组成。

                用户相关:进程地址空间(包括代码段、数据婴堆和栈、共享库……)

                寄存器相关:程序计数器、指令寄存器、程序状态寄存器、栈指针、通用寄存器等的值。

                内核相关:

                        静态部分:PCB及各种资源数据结构。

                        动态部分:内核栈(不同进程在进入内核后使用不同的内核栈)


上下文(CONTEXT)切换

        将CPU硬件状态从一个进程换到另一个进程的过程称为上下文切换

        进程运行时,其硬件状态保存在CPU上的寄存器中。

                寄存器:程序计数器、程序状态寄存器、栈指针、通用寄存器、其他控制寄存器的值。

        进程不运行时,这些寄存器的值保存在进程控制块PCB中;当操作系统要运行一个新的进程时,将PCB中的相关值送到对应的寄存器中。

3.5、线程的引入

为什么在进程中再派生线程?

        三个理由:

                应用的需要

                开销的考虑

                性能的考虑

应用的需要

        略

开销的考虑

        进程相关的操作:

                创建进程

                撤消进程

                进程通信

                进程切换

        >时间/空间开销大,限制了并发度的提高。

        

        线程的开销小

                创建一个新线程花费时间少(撤销亦如此)

                两个线程切换花费时间

                线程之间相互通信无须调用内核(同一进程内的线程共享内存和文件)

性能的考虑

        略

线程的基本概念(在同一进程增加了多个执行序列)

        进程的两个基本属性:资源的拥有者(进程还是资源的拥有者)、CPU调度单位(线程继承了这一属性)。

        线程:进程中的一个运行实体是CPU的调度单位有时将线程称为轻量级进程

线程的属性

        线程:

                有标示符ID。

                有状态及状态转换        →        需要提供一些操作。

                不运行时需要保存的上下文。

                        有上下文环境:程序计数器等寄存器。

                有自己的栈和栈指针。

                共享所在进程的地址空间和其他资源。

                可以创建、撤消另一个线程程序。开始是以一个单线程进程方式运行的。

3.6、线程机制的实现

线程的实现

        用户级线程

        核心级线程

        混合-两者结合方法

用户级线程

        在用户空间建立线程库:提供一组管理线程的过程。

        运行时系统(Run-time system):完成线程的管理工作(操作、线程表)。

        内核管理的还是进程,不知道线程的存在。

        线程切换不需要内核态特权。

        例子:UNIX

        例子:POSIX线程库--PTHREAD

                POSlX(Portable Operating System Interface):多线程编程接口,以线程库方式提供给用户。

Thread callDescription
Pthread_createCreate a new thread
Pthread_exitTerminate the calling thread
Pthread_joinWait for a specific thread to exit
Pthread_yieldRelease the CPU to let another thread run
Pthread_attr_initCreate and initialize a thread's attribute structure
Pthread_attr_destroyRerove a thread's attribute structure

        优点:
                线程切换快。
                调度算法是应用程序特定的。

                用户级线程可运行在任何操作系统上(只需要实现线程库)。
        缺点:
                内核只将处理器分配给进程,同一进程中的两个线程不能同时运行于两个处理器上。

                大多数系统调用是阻塞的,因此,由于内核阻塞进程,故进程中所有线程也被阻塞。

核心级线程(KERNEL LEVEL THREAD)

        内核管理所有线程管理并向应用程序提供API接口。

        内核维护进程和线程的上下文。

        线程的切换需要内核支持。

        以线程为基础进行调度。

        例子:Windows。

混合模型(多个用户级线程多路复用多个内核级线程)

        线程创建在用户空间完成。

        线程调度等在核心态完成。

        例子:Solaris。

四、处理器调度(CPU调度)

4.1、处理器调度的相关概念

CPU调度

        其任务是控制、协调进程对CPU的竞争。

        即按一定的调度算法从就绪队列中选择一个进程把CPU的使用权交给被选中的进程。

        如果没有就绪进程,系统会安排一个系统空闲进程或idle进程。

        系统场景

                N个进程就绪、等待上CPU运行。

                M个CPU,M≥1。

                需要决策:给哪一个进程分配哪一个CPU?

CPU调度要解决的三个问题

        WHAT:按什么原则选择下一个要执行的进程(调度算法)。

        WHEN:何时进行选择(调度时机)。

        HOW:如何让被选中的进程上CPU运行(调度过程,即进程的上下文切换)。

CPU调度的时机(内核对中断/异常/系统调用处理后返回到用户态时)

        进程正常终止或由于某种错误而终止。

        新进程创建或一个等待进程变成就绪。

        当一个进程从运行态进入阻塞态。

        当一个进程从运行态变为就绪态。

        CPU调度的过程:事件发生        →        当前运行的进程暂停运行        →        硬件机制响应后        →        进入操作系统,处理相应的事件        →        结束处理后:某些进程的状态会发生变化,也可能又创建了一些新的进程        →        就绪队列改变了        →        需要进程调度根据预设的调度算法从就绪队列选一个进程。

        典型的事件举例:

                创建、唤醒、退出等进程控制操作。

                进程等待I/0、I/0中断。

                时钟中断,如:时间片用完、计时器到时。

                进程执行过程中出现abort异常。

调度过程--进程切换

        进程调度程序从就绪队列选择了要运行的进程:

                这个进程可以是刚刚被暂停执行的进程,也可能是另一个新的进程。

        进程切换:是指一个进程让出处理器,由另一个进程占用处理器的过程。

        进程切换主要包括两部分工作:

                切换全局页目录以加载一个新的地址空间。

                切换内核栈和硬件上下文,其中硬件上下文包括了内核执行新进程需要的全部信息,如CPU相关寄存器。

        切换过程包括了对原来运行进程各种状态的保存和对新的进程各种状态的恢复。

上下文切换具体步骤

        场景:进程A下CPU,进程B上CPU。

        保存进程A的上下文环境(程序计数器、程序状态字、其他寄存器……)

        用新状态和其他相关信息更新进程A的PCB。

        把进程A移至合适的队列(就绪、阻塞......)。

        将进程B的状态设置为运行态。

        从进程B的PCB中恢复上下文(程序计数器、程序状态字、其他寄存器......)

上下文切换开销(COST)

        直接开销:内核完成切换所用的CPU时间。

                保存和恢复寄存器………。

                切换地址空间(相关指令比较昂贵)。

        间接开销:

                高速缓存(Cache)、缓冲区缓存(Buffer Cache)和TLB(Translation Lookup Buffer)失效。

调度算法衡量指标

        吞吐量Throughput:每单位时间完成的进程数目

        周转时间TT(Turnaround Time):每个进程从提出请求到运行完成的时间

        响应时间RT(Response Time):从提出请求到第一次回应的时间

        其他

                CPU 利用率(CPU Utilization):CPU做有效工作的时间比例

                等待时间(Waiting time):每个进程在就绪队列(ready queue)中等待的时间

4.2、设计调度算法要考虑的几个问题

设计调度算法时要考虑以下几个问题:

        进程控制块PCB中需要记录哪些与CPU调度有关的信息。

        进程优先级及就绪队列的组织。

        抢占式调度与非抢占式调度。

        I/0密集型与CPU密集型进程。

        时间片。

进程优先级

        静态优先级:进程创建时指定,运行过程中不再改变。

        动态优先级:进程创建时指定了一个优先级,运行过程中可以动态变化。

                如:等待时间较长的进程可提升其优先级。

进程就绪队列组织

        按优先级排队。

        时间片用完降级。

抢占与非抢占(指占用CPU的方式)

        可抢占式Preemptive(可剥夺式)

                当有比正在运行的进程优先级更高的进程就绪时,系统可强行剥夺正在运行进程的CPU,提供给具有更高优先级的进程使用。

        不可抢占式Non-preemptive(不可剥夺式)

                某一进程被调度运行后,除非由于它白身的原因不能运行,否则一直运行下去。


I/0密集型与CPU密集型进程

        按进程执行过程中的行为划分:

                l/O密集型或I/0型(l/O-bound):频繁的进行I/O,通常会花费很多时间等待I/O操作的完成。

        CPU密集型或CPU型或计算密集型(CPU-bound):需要大量的CPU时间进行计算。

时间片

        一个时间段,分配给调度上CPU的进程,确定了允许该进程运行的时间长度。

        如何选择时间片呢?考虑因素:

                进程切换队的开销。

                对响应时间的要求。

                就绪进程个数。

                CPU能力。

                进程的行为。

4.3、批处理系统的调度算法

批处理系统中采用的调度算法:

        先来先服务(FCFS-First Come First Serve)

        最短作业优先(SJF-Shortest Job First)

        最短剩余时间优先(SRTN-Shortest Remaining Time Next)

        最高相应比优先(HRRN-Highest Response Ratio Next)

        需要考虑吞吐量、周转时间、CPU利用率、公平、平衡。

先来先服务(FCFS-First Come First Serve)

        先进先出(FIFO-First In First Out)。

        按照进程就绪的先后顺序使用CPU。

        非抢占式。

        优缺点:

                公平。

                实现简单。

                长进程后面的短进程需要等很长时间,不利于用户体验。

        FCFS调度算法举例:

                例子:

                        三个进程按顺序就绪:P1、P2、P3。

                        进程P1执行需要24s,P2和P3各需要3s。

                        假设采用FCFS调度算法。

                        则:

                                吞吐量:3jobs/30s=0.1jobs/s。

                                周转时间TT:

                                        P1:24;P2:27;P3:30。

                                平均周转时间:27s。

最短作业优先(SJF-Shortest Job First)

        具有最短完成时间的进程优先执行。

        非抢占式。

最短剩余时间优先(SRTN-Shortest Remaining Time Next)

        SJF抢占式版本,即当一个新就绪的进程比当前运行进程具有更短的完成时间时,系统抢占当前进程,选择新就绪的进程执行。

        思路:先完成短的作业,去改善短作业的周转时间。

        优缺点:

                最短的平均周转时间。

                        在所有进程同时可运行时,采用SJF调度算法可以得到最短的平均周转时间。

                不公平。

                        源源不断的短任务到来,可能使长的任务长时间得不到运行,产生“饥饿”现象(starvation)。

最高相应比优先(HRRN-Highest Response Ratio Next)

        是一个综合的算法。

        调度时,首先计算每个进程的响应比R;之后总是选择R最高的进程执行。

                响应比R = 周转时间 / 处理时间 = (处理时间 + 等待时间) / 处理时间 = 1 + (等待时间 / 处理时间)。

4.4、交互式系统的调度算法

交互式系统中采用的调度算法

        轮转调度(RR-Round Robin)。

        最高优先级调度(HPF-Highest Priority First)。

        多级反馈队列(Multiple feedback queue)。

        最短进程优先(Shortest Process Next)。

        考虑响应时间、公平、平衡。

时间片轮转调度算法

        目标:为短任务改善平均响应时间。

        解决问题的思路:

                周期性切换。

                每个进程分配一个时间片。

                时钟中断        →        轮换。

        如何选择合适的时间片?

                太长(大于典型的交互时间):

                        降级为先来先服务算法。

                        延长短进程的响应时间。

                太短(小于典型的交互时间):

                        进程切换浪费CPU时间。

        优缺点:

                公平。

                有利于交互式计算,响应时间快。

                由于进程切换,时间片轮转算法要花费较高的开销。

                        假设时间片10ms,如果进程切换花费0.1ms,则CPU开销约占1%。

                RR对不同大小的进程是有利的。RR对相同大小的进程是不利的。

最高优先级调度算法

        选择优先级最高的进程投入运行。

        通常:

                系统进程优先级高于用户进程。

                前台进程优先级高于后台进程。

                操作系统更偏好I/O型进程。

        优先级可以是静态不变的,也可以动态调整。

                优先数可以决定优先级。

        就绪队列可以按照优先级组织。

        实现简单;不公平。

        会使优先级低的进程产生饥饿现象。

优先级反转问题(基于优先级的抢占式 )

        Priority Inversion,又称:优先级反置、翻转、倒挂。

        现象:

                一个低优先级进程持有一个高优先级进程所需要的资源,使得高优先级进程等待低优先级进程运行。

        影响:

                系统错误。

                高优先级进程停滞不前,导致系统性能降低。

        解决方案:

                设置优先级上限。

                优先级继承。

                使用中断禁止。

五、同步互斥机制

5.1、进程的并发执行

并发是所有问题产生的基础。

并发是操作系统设计的基础。

从进程的特征出发:

        并发。

                进程的执行是间断性的。

                进程的相对执行速度不可预测。

        共享。

                进程/线程之间的制约性。

        不确定性。

                进程执行的结果与其执行的相对速度有关,是不确定的。

5.2、进程互斥

由于各进程要求使用共享资源(变量、文件等),而这些资源需要排他性使用,各进程之间竞争使用这些资源。这一关系称为进程互斥。

临界资源:系统中某些资源一次只允许一个进程使用,称这样的资源为临界资源或互斥资源或共享变量。

临界区(互斥区):各个进程中对某个临界资源(共享变量)实施操作的程序片段.

临界区(互斥区)的使用原则

        没有进程在临界区时,想进入临界区的进程可进入。

        不允许两个进程同时处于其临界区中。

        临界区外运行的进程不得阻塞其他进程进入临界区。

        不得使进程无限期等待进入临界区。

实现进程互斥的方案

        软件方案

                Dekker解法、Peterson解法

        硬件方案

                屏蔽中断、TSL(XCHG)指令

5.3、进程互斥的软件解决方案

5.4、进程互斥的硬件解决方案

5.5、进程同步

进程同步:指系统中多个进程中发生的事件存在某种时序关系,需要相互合作,共同完成一项任务。

具体地说,一个进程运行到某一点时要求另一伙伴进程为它提供消息,在未获得消息之前,该进程进入阻塞态,获得消息后被唤醒进入就绪态。

5.6、信号量及PV操作

信号量

        一个特殊变量。

        用于进程间传递信息的一个整数值。

        定义如下:

                struc semaphore

                {

                        int count;

                        queueType queue;

                }

        信号量说明:semaphore s;

        对信号量可以实施的操作:初始化、P和V(P、V分别是荷兰语的test(proberen)和increment(verhogen))。

P(down,semWait)、V(up,semsignal)操作定义

P(s)
{
    s.count--;
    if (s.count < 0)
    {
        该进程状态置为阻塞状态;
        将该进程插入相应的等待队列s.queue末尾;
        重新调度;
    }
}

V(s)
{
    s.count++;
    if (s.count <= 0)
    {
        唤醒相应等待队列s.queue中等待的一个进程;
        改变其状态为就绪态,并将其插入就绪队列;
    }
}

        P、V操作为原语操作。

        在信号量上定义了三个操作:初始化(非负数)、P操作、V操作。

        最初提出的是二元信号量(解决互斥)。之后,推广到一般信号量(多值)或计数信号量(解决同步)

用PV操作解决进程间互斥问题

        分析并发进程的关键活动,划定临界区。

        设置信号量 mutex,初值为1。

        在临界区前实施P(mutex)。

        在临界区之后实施V(mutex)。

5.7、生产者消费者问题

5.8、读者写者问题

六、同步互斥机制与通信机制

6.1、管程的基本概念

6.2、HOARE管程

6.3、管程的应用

6.4、MESA管程

6.5 PTHREAD中的同步机制

6.6、进程间通信IPC

6.7、典型操作系统中的IPC机制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值