嵌入式-操作系统yroccry

第一章操作系统简介

计算机操作系统的设计与实现技术是计算机科学领域的一个重要研究课题,也是计算机科学相关领域的工作者理解计算机工作基本原理、深入认识计算机软件驱动硬件完成特定功能过程的关键环节。本章将从操作系统的作用、功能、特征、发展及软件体系结构等不同角度简要介绍操作系统。目的是使读者了解什么是操作系统,操作系统能做什么,为什么计算机系统中需要操作系统的支持。为了使读者更好地理解后续章节的内容,在本章的最后一节还将介绍指令的执行过程。

第一节 什么是操作系统

操作系统(OperatingSystem,OS)是一种复杂的系统软件,是不同程序代码、数据结构、数据初始化文件的集合,可执行。例如,常用的Linux、Windows7和Windows10等。通常所说的装“系统”,就是指装“操作系统”。操作系统提供计算机用户与计算机硬件之间的接口,并管理计算机软件和硬件资源。操作系统本身并不向用户提供可直接使用的功能,一台仅装有操作系统的计算机对于用户而 言几乎是没有用的,但是它为用户可直接使用的应用程序的运行提供了环境,并为应用程序的开发提供平台,使应用程序的开发变得简单、高效。

操作系统是覆盖在裸机上的第一层软件,编译程序、数据库管理系统及其他应用程序都运行在操作系统之上,操作系统为这些软件提供运行环境。

下面从不同角度说明什么是操作系统。

一、用户与硬件之间的接口

为什么说:“操作系统提供了计算机用户与计算机硬件之间的接口?”接口是两个不同组成部分的交接面。在计算机专业领域,接口分为硬件接口和软件接口,硬件接口如USB接口、串口和并口,软件接口如C语言中的函数调用printf()。

计算机的所有功能最终都是由硬件的操作来实现的。但是,通常使用如C、C++、Java和 Python等高级程序设计语言所编写的应用程序中并没有直接操作硬件的语句和指令,那为什么这些程序依然能够操纵显示器、打印机和绘图仪等硬件,通过硬件对程序的执行得到执行结果,完成特定的功能呢?这是因为应用程序是在操作系统上运行的,而对硬件的控制过程都封装在操作系统的核心程序中了。

例如,执行用户程序中的printf(),不需要在用户程序中写直接操作打印机或显卡的指令,但是在操作系统上运行的用户程序通过接口printf(),最终调用到操作系统中实现输出功能的函数,其中包括了驱动硬件的指令,从而实现了对硬件的操作。这个过程比较漫长,实际上在printf()函数中又调用了其他的库函数,经过库函数的层层调用之后,调用操作系统中的特殊函数和驱动程序,控制硬件完成显示或者打印输出的功能。

因为有了操作系统对硬件的抽象,而且操作系统为应用程序提供了运行环境,所以在操作系统上编写和运行应用程序就简单多了。例如,在Windows操作系统下用C语言编写从磁盘读文件的程序,只需使用fopen( )、fread()和fclose()这几个函数。但是在没有操作系统的裸机上要写一个可以读文件的程序就复杂多了,必须清楚要读的文件在磁盘上的物理位置,即文件数据在磁盘上的柱面号、磁道号和扇区号,还需要知道读入的数据放在内存的什么位置,然后调用相应的指令序列完成读操作。

接下来通过以下两个实例来说明,在有操作系统的环境中使用高级语言开发应用程序比在无操作系统的裸机上开发相同功能的应用程序要简单、快捷。

上面这段程序,先执行了一次int13h中断对磁盘进行初始化,通过对ah、dl清零对驱动器复位。然后根据逻辑扇区号计算出文件data.dat的第一个扇区在磁盘上的绝对物理地址。这个地址包括了data.dat的第一个逻辑扇区在磁盘上的柱面号、磁头号和起始扇区号。最后,程序将这些地址信息和功能号写人指定的寄存器,然后再次执行int13h中断,执行一次读操作。

大多数应用软件的开发者可以在不了解计算机硬件接口的情况下编写大量的应用程序,这是因为有了操作系统和大量的库函数完成了公用的、复杂的、可以被应用程序调用的功能。由以上两个实例的对比可以看出,操作系统屏蔽了对硬件操作的细节,提供了计算机用户与计算机硬件之间的接口,并且通过这个接口使应用程序的开发变得简单、高效。

操作系统必须完成的两个主要目标如下。

1)与硬件部分相互作用,为包含在硬件平台上的所有底层可编程部件提供服务。

例如,要使用显示器,必须为驱动显示器工作的一些寄存器赋值,以便让显示器“知道自己要以什么样的背景颜色和前景颜色显示什么内容”。

2)为运行在计算机系统上的应用程序(即所谓用户程序)提供执行环境。

高级语言的应用程序是不能在裸机上运行的,必须运行在操作系统上,由操作系统为应用软件的执行分配必要的软件和硬件资源,并对这些资源进行有效的管理。

二、资源的管理者

现代计算机系统的一个重要特点就是支持多任务,即允许在同一个系统内同时驻留多个应用程序。多个应用程序共同使用计算机硬件和软件资源时,就需要操作系统对这些资源进行有效的管理。一方面保证用户程序的顺利执行,另一方面使计算机系统资源得到尽可能高效的利用,保证计算机系统的高性能。操作系统所管理的资源主要包括处理机、内存、设备和文件,在网络操作系统中还包括网卡、带宽等。下面对操作系统的主要功能进行说明。

1.处理机管理 本书讲述的是多任务操作系统的实现原理。由于程序的执行必须依靠处理机,任意时刻

处理机都只能执行一个程序流。因此,在单处理机系统中执行多个程序流,必须由操作系统的处理机调度程序来管理处理机的分配,以使多个程序共享处理机,从宏观上看多个程序能同时顺利执行。在多处理机系统中,也需要操作系统对多个处理机在多任务的情况下进行有效的管理。

2.内存管理

在多任务系统中,内存不再是独占资源,而是可能被多个应用程序共同占用。如何为多个应用程序分配内存并使不同应用程序的地址空间互不干扰,如何在程序执行完毕后回收其所占内存,以及完成逻辑地址到物理地址的转换,都是操作系统内存管理程序要完成的功能。

3.设备管理

设备管理主要完成接受用户的I/O请求、为用户分配I/O设备、管理I/O缓存和驱动I/0设备等功能。

4.文件管理

计算机系统把大量需要长时间保留的数据信息以文件的形式存放在外存储设备中(如硬盘、光盘、磁带和U盘),操作系统通过自己的文件管理程序完成外存空间的分配、回收、

文件的按名存取、文件的组织、共享与保护等功能。

第二节操作系统的发展

操作系统是在解决计算机系统所面临的问题中诞生并发展的自然结果。操作系统的发展从时间顺序上经历了从无操作系统到单道批处理系统、多道程序系统(多道批处理系统、分时系统)的发展过程。随着计算机应用领域的扩大、计算机体系结构的多样化,又出现了微机操作系统、网络操作系统、实时操作系统、嵌入式操作系统和物联网操作系统。本节以计算机发展的时间为线索,说明操作系统是如何在解决计算机系统面临的问题中自然发展的。

一、无操作系统

第一代计算机(1945~1955年)使用电子管作为主要的电子器件,用插件板上的硬连线或穿孔卡片表示程序,没有用来存储程序的内存,无操作系统。

以1946年诞生于宾夕法尼亚大学的第一台实用电子计算机“埃尼阿克”(ENIAC)为例,它没有真正的内存,只有20个字节的寄存器用来存储数字。每个字节10位,也就是只有200 位的“存储”容量,无法支持存储程序。操作系统需要常驻内存,当时的情况是不仅硬件技术无法支持操作系统的运行,理论研究领域也没有操作系统的概念。使用“埃尼阿克”的方式是程序员用电路的连接方式表示算法,一旦算法发生改变,必须变更电路的连接方式。程序员在使用“埃尼阿克”进行计算工作之前,先用插件板上的电路连接表示程序,同时预约好一段上机时间。然后到机房中将插件板接到计算机中,开启计算机开关,开始一次运算。显然,一个用户程序进入计算机和退出计算机系统都需要人工干预,计算机无法自动完成程序的加载和卸载。因此,整个计算机系统处于运行一因等待人工操作暂停一运行,这样一种不能连续自动工作的状态。

二、单道批处理系统

第二代计算机(1955~1965年)使用的主要电子器件是晶体管,开始使用磁性存储设备,内外存容量增加,计算机运算速度提高,出现了早期的单道批处理系统。

在本书中,将用户程序及程序处理的数据统称为作业。在单道批处理系统出现以前,使用计算机的方式是操作员把作业挂到输入设备上,启动机器,运算结束取结果。典型的情况是程序员用穿孔卡片表示程序和数据,需要运行这些穿孔卡片表示的作业时,程序员把卡片盒交给输入室的计算机操作员,然后程序员开始等待输出结果。计算机运行完当前作业后,将计算结果从打印机上输出。操作员到打印机上撕下运算结果送到输出室,程序员可以在这里取到自己作业运行的输出结果。

这种对计算机的人工控制模式存在的问题是,机器速度很快的时候CPU长时间等待人工操作,造成了CPU资源的严重浪费。该问题的解决方案是利用磁性存储设备提高输入/输出(简写为I/O)速度。同时,系统程序常驻内存并自动装入作业,撤销作业,输出运算结果。

这里更详细地描述这一解决问题的思路。操作员在输入室收集全部作业,然后用一台相对便宜的、专门用来输入的计算机把作业从穿孔卡片输入到磁带上,一盘磁带可以存储多个作业。然后,操作员把存有批量作业的磁带装到磁带机上。操作员在专门用于计算的、性能较高的计算机上装入早期的操作系统,也称监视程序,它能自动从磁带读入作业并使之运行,把作业运行结果写入专门存放输出结果的磁带上。每当一个作业运行结束后,操作系统自动从磁带中读入下一个作业并使之运行。当一批作业运行完毕后,操作员取下输入和输出磁带,将输入磁带换成下一批作业,并把输出磁带装到专门用于输出的计算机上,打印输出结果。其过程如图1-2所示。

这一时期的操作系统是单道批处理系统,内存中只能驻留一道用户作业,CPU和内存资源被用户作业独占。程序是指令的集合,程序的执行是CPU依次、逐条执行指令的过程。

当执行到输人/输出指令时,启动设备控制器工作。在设备控制器控制设备完成输人/输出(磁带和内存之间的数据传输)的一段时间内是不需要CPU干预的。在单道批处理系统的管理下,此时间段内CPU空闲,无事可做。对于租用计算机的用户而言,损失了CPU的机时,而计算机系统损失了系统的吞吐量。吞吐量是指单位时间内计算机系统处理的作业量。

三、多道程序系统

随着电子技术的发展,计算机开始采用集成电路芯片作为主要的电子器件,IBM360是第一个采用小规模集成电路芯片的主流机型。这个时期,生产厂商试图通过生产通用计算机,把用于科学计算、工程计算及磁带归档、打印处理的两类计算机合二为一。但是通用计算机存在一个问题,对于CPU操作密集型的作业(即使用CPU频率高的作业),输入、输出操作较少,CPU利用率比较高。但是,当通用计算机用于运行输入和输出密集型的作业时,由于CPU频繁等待输入、输出,而CPU在等待输人、输出完成的过程中只能原地踏步,无法进行任何有效的工作,使CPU的浪费最多可达到80%~90%。为了解决这一问题,提高 CPU的利用率,提出了多道程序系统的概念。OS/360是IBM开发的第一个多道程序系统。

第一个通用分时系统CTSS(Compatible Time Sharing System)是麻省理工学院于1962年在一台改装过的IBM7094上开发成功的,后续又出现了MULTICS(MULTiplexed Information and Computing Service)、UNIX、Linux和Windows等著名的既支持多道批处理功能、又支持分时

功能的多道程序系统。

四、微机操作系统

随着个人计算机的出现,微机操作系统应运而生。第一个微机操作系统是Intel公司的顾问Gary Kildall编写的CP/M(Control Program for Microcomputer)系统。这是一个磁盘操作系统,用于Intel8080。1977年,CP/M被重写,使其可以在使用Intel 8080、ZilogZ80及其他 CPU芯片的多种微型计算机上运行。从此,CP/M在微机操作系统市场风行了几年,成为了最著名的8位操作系统。

20世纪80年代初,IBM进军个人计算机市场。在IBM向Digital Research公司提出为 IBM个人计算机编写16位操作系统时,Digital Research拒绝了IBM的请求。这无疑是Digit- al Research最槽糕的一次商业决策。此时,一直与IBM有联系的比尔·盖茨向一家计算机制造商购买了DOS(DiskOperating System)操作系统。后来,经过对DOS 的修改,形成了新的DOS 版本MS-DOS(MicroSoft Disk Operating System)。以后,比尔·盖茨的微软公司采取了将MS-DOS与硬件捆绑销售的策略。随着CPU的不断升级,微软及时更新MS-DOS,使之日臻完善,成为微机操作系统的主流。

受到Macintosh 的影响,1985 年微软开始构建Windows操作系统。时至今日,虽然面临各种挑战,Windows操作系统依然是微机操作系统的主流。目前,除Windows系列的微机操作系统之外,还有Linux、ChromeOS和MacOS等一些支持个人计算机的操作系统。

五、实时操作系统

随着计算机被广泛应用于各种工业现场的自动控制、智能机器人、海底探测和航空航天等领域,出现了各种实时系统。实时系统是支持实时计算的系统。实时计算的正确性不仅依赖于系统计算的逻辑结果,还依赖于产生正确结果的时间。简单的解释就是,实时系统不仅要求系统能正确地计算出1加1等于2,而且要求必须在规定的时间内计算出1加1等于2。如果计算结果正确,但是时间超过了规定时间,依然被认为计算出错。例如,锅炉温度和压力自动控制系统、重病监测系统等都属于实时系统。

实时系统可以使用操作系统,也可以不用操作系统。在高端的实时系统中通常都有高可靠性和支持实时资源调度的实时操作系统(Real-time Operating System,RTOS)。VxWorks操作系统是美国WindRiver公司于1983年设计开发的一种嵌入式实时操作系统;μC/OS-II是一种被广泛应用于微处理器、微控制器和数字信号处理器的开源实时多任务操作系统内核; Linux系统也支持实时性。

六、批处理系统、分时系统、实时系统的特点

1.单道批处理系统的特点

单道批处理系统内存中只有一道作业,可以自动成批处理作业,其特点如下。

(1)自动性

单道批处理系统使计算机能够在操作系统控制下,自动地将作业从外存装入内存运行。当作业运行完毕后,自动撤销已运行完毕的作业,并依次从外存装入下一个作业,使之运行。

(2)顺序性

存放在外存中的作业按顺序依次被装入内存运行,先进入内存的作业先运行完毕。

(3)单道性

任何时刻内存中只有一道作业。即操作系统每次只能从外存装人一个作业进入内存。只有当该作业正常或异常结束,才能将下一个作业装入内存。

单道批处理系统与无操作系统的计算机系统相比而言,减少了等待人工操作的时间。但是单道批处理系统中,由于作业独占CPU和内存,当作业进行I/O时,CPU只能等待I/O完成而无事可做,使得CPU资源不能得到充分利用。

2、多道批处理系统的特点

在多道批处理系统中,用户所提交的作业都先存放在外存中并排成一个队列,该队列被称为“后备作业队列”。由操作系统的作业调度程序按一定策略从后备作业队列中选择若干个作业调入内存,使它们共享CPU和系统中的各种资源,以达到提高资源利用率和系统吞吐量的目的。与单道批处理系统相比,多道批处理系统支持多道程序驻留内存,CPU可以不再空闲等待I/0。多道批处理系统的特点如下。

(1)多道性

在内存中可同时驻留多道程序,当在CPU上运行的作业提出I/O请求后,该CPU可以执行其他作业,从而有效地提高了系统资源的利用率和吞吐量。

(2)无序性

多个作业完成的先后顺序与它们进入内存的顺序之间没有严格的对应关系。同时驻留在内存中的作业,其获得CPU的顺序和执行的进度无法预知,先进入内存的作业不一定先被调度,也不一定先执行完。

(3)调度性

多道程序系统必须具有作业调度和进程调度功能。作业调度用来从后备作业队列中选择一个或多个要被装入内存的作业。进程调度程序用来从内存中选择一个(单CPU系统)或多个(多CPU系统)进程,使其在CPU上运行。

(4)复杂性

由于多道程序系统中的作业共享CPU、内存、外设和文件,程序并发执行,多道程序系统必须具有处理机管理、内存管理、I/O设备管理、文件管理和作业管理的功能,分时系统还必须解决终端用户管理的问题。因此,其功能和实现技术都比单道批处理系统复杂得多。

多道批处理系统的优点是能够提高CPU、内存和I/O设备的利用率和系统的吞吐量。多道批处理系统的缺点是系统平均周转时间长,缺乏交互能力。周转时间是指从作业被提交给系统开始到作业完成为止的时间。平均周转时间是指所有作业的周转时间之和与作业数量的比值。

3.分时系统的特点

分时操作系统允许多个用户通过终端同时使用计算机。分时操作系统是多道程序系统的自然延伸,支持多个用户任务同时驻留内存,每个用户通过终端与主机交互时都能得到快速

响应。

分时系统的特点是多路性、独立性、及时性和交互性。多路性是指允许在一台主机上同时连接多台联机终端。独立性是指各终端用户彼此独立操作,互不干扰。及时性是指用户请求能在很短的时间内获得响应。交互性是指用户可以通过终端与系统进行广泛的人机对话。分时系统的优点是向用户提供了人机交互的方便性,使多个用户可以通过不同的终端共享主机。

分时系统的实现需要解决两个关键问题,即及时接收和及时处理。同时连接多个用户终端的分时系统要能及时接收用户的命令或数据,新用户命令到来时,尚未处理的用户命令要通过缓冲区来妥善保存。此外,分时系统要能及时处理用户的交互命令,使系统的响应时间得到保证。为了实现这一目标,应该使所有的用户任务都直接进入内存,并在很短的时间内使每个任务都运行一次。

4.实时系统的特点

实时系统主要用于实时控制和实时信息处理领域。实时系统必须能及时响应外部事件的请求,在规定的时间内完成对该事件的处理,并控制所有实时任务协调一致地运行。与分时系统相比,实时系统具有以下特点。

(1)多路性

实时系统的多路性除具有与分时系统相同的特点外,主要表现在经常对多路的现场信息进行采集,以及对多个对象或多个执行机构进行控制。

(2)独立性

实时信息系统与分时系统一样,每个终端用户在向实时系统提出服务请求时,是彼此独立地操作,互不干扰。而在实时控制系统中,信息的采集和对对象的控制也是彼此互不干扰。

(3)及时性

实时信息处理系统对实时性的要求是以人所能接受的等待时间来确定的,而实时控制系统的及时性则是以控制对象所要求的开始截止时间或完成截止时间来确定的。

(4)交互性

实时信息系统的交互性仅限于访问系统某些特定的专用服务程序。

(5)可靠性

实时系统比分时系统要求有更高的可靠性。因为任何实时系统的错误都可能带来巨大的经济损失,甚至危及生命安全。因此,在实时系统中,往往采取多级容错措施来保证系统安全和数据安全。

需要注意的是,批处理系统、分时系统和实时系统是三种基本的操作系统类型,而一个实际的操作系统可能兼有三者或其中两者的功能特点。

七、操作系统产品现状

1.主机操作系统

主机操作系统是运行在大型主机上的操作系统,主要提供三类服务:批处理、事物处理和分时处理。批处理系统处理不需要交互式用户干预的周期性作业,保险公司的索赔处理或者连锁商店的销售报告通常以批处理的方式完成。

事务处理系统负责大量的小请求。例如,银行的支票处理或航班预定。每个业务量都很小,但是系统必须每秒处理成百上千个业务,需要很高的处理速度。

分时系统允许多个远程用户同时在计算机上工作,执行命令或处理作业。

一个大型主机操作系统通常同时具有批处理、事务处理和分时处理的功能。IBM的OS/360和OS/390是典型的大型主机操作系统。Linux和UNIX的一些版本也是很多大型机常用

的操作系统。

2.服务器操作系统服务器操作系统是运行在网络服务器上的操作系统,可以通过网络同时为众多用户服务,允许用户共享硬件和软件资源。服务器可提供打印服务、文件服务和Web服务。典型的服务器操作系统有Solaris、FreeBSD、Linux和Windows Server200X。Linux作为影响力量大的开源软件,其内核根据不同的需要被定制,广泛地应用于服务器、PC和移动设备。一些互联网公司(如腾讯、阿里巴巴等)使用Linux内核的不同发行版作为自己的网络服务器操

作系统。

3. 微机操作系统

微机操作系统也称个人机操作系统,现代微机操作系统都支持多道程序处理,就是通常所说的支持多任务。微机操作系统为单个用户提供良好的应用环境和应用软件开发环境。常见的微机操作系统有Windows的个人计算机操作系统系列、Linux的不同发行版、Macintosh和ChromeOS 等。

4.嵌入式操作系统

嵌人式系统的概念出现在20世纪70年代,是宿主于非计算机设备中的计算机系统。嵌入式操作系统是运行于嵌入式设备中的操作系统。第一个商用嵌入式操作系统VRTX32出现于1981年。20世纪80年代的嵌入式操作系统主要用于军事和电信产品,如VRTX32和 PSOS。20世纪90年代,微内核设计技术和模块化的设计思想开始渗入嵌入式操作系统。互联网的迅速发展对嵌入式操作系统提出了新的要求,为了方便使用大量现有的软件代码,嵌入式操作系统需要支持标准的API。这个时期出现了几十种产品,具有代表性的有VxWork、 QNX、WinCE 和Android等。嵌入式操作系统在技术上的特征是设计上采用更易于移植的方式,以适应越来越多的新处理器;开放源码,提高性能,保证高可靠性。嵌入式 Linux在消费电子设备中得以广泛应用。

目前,应用于嵌入式系统的实时操作系统产品非常多。在物联网快速发展的情况下,出现了物联网操作系统。物联网操作系统本质上是连接在物联网的各种可计算设备中的操作系统,也就是嵌人式操作系统。物联网操作系统的产品较为丰富,如苹果公司的iOs、谷歌的 Android Things、微软的Windows10IoT Core和开源物联网项目FreeRTOS等。

嵌入式操作系统的特征是小巧、实时性、可装卸、代码固化、弱交互性、强稳定性、接口统一、低能耗。

嵌入式操作系统的应用领域有掌上电脑、智能手机、数码相机、自动售货机、自动取款机、工业控制设备、军工装备、游戏机、医疗设备和网络设备等。

第三节操作系统的特征

现代操作系统都支持多任务,具有并发、共享、虚拟和异步性特征。

1.并发

是有区别的两个不同的概念,并行是指多个事件同时发生。 并发是指两个或多个事件在同一时间间隔内发生。并发强调“同一时间间隔”,与并行

以单CPU多任务的操作系统为例,当说两个程序并发执行时,是指从宏观上看这两个

程序同时在向前推进。例如,可以在一台单CPU单核的笔记本电脑中一边运行音频播放程序听歌曲,一边用Micro Office Word编辑文档,编辑程序在工作的同时音频播放程序也在工作。但是,在单CPU单核的系统中,任意时刻只能有一个程序流在CPU上执行,要么是编辑文档程序,要么是音频播放程序。之所以用户能感觉到两个程序似乎在同时工作,而且互不干扰,是因为操作系统使两个程序在CPU上快速地轮流交替执行,实现了“并发”的功能。

2.共享

共享是指系统中的资源可供内存中多个并发执行的进程共同使用。资源共享有两种方式,即互斥共享和同时共享。

互斥共享是指任意时刻一种资源只能被一个进程访问,当一个进程访问资源时,其他进程必须等待,直到资源被进程访问完毕,释放访问权。例如打印机的访问,如果不采取互斥访问的方式,可能会把多个进程的输出内容打印到同一页打印纸上。

同时,共享是指从宏观上看,资源可以被多个进程同时访问,如对磁盘的访问。虽然任意时刻只能有一个程序访问某个磁盘。但是,多个程序可以在短时间内轮流访问该磁盘,从用户的角度看,多个用户程序可以同时发送磁盘访问命令,并可以同时得到响应。从宏观上看,磁盘可以被多个用户程序同时访问。

并发与共享的关系是相互依赖的。如果系统不支持并发,资源的使用都是独占的,不需要共享资源。另一方面,如果不能实现有效的资源共享,并发就不可能得到很好的支持。

3.虚拟

虚拟是指通过某种技术把一个物理实体变成若干逻辑上的对应物。物理实体是实际存在的,而虚拟仅仅是用户感觉到的。如虚拟打印机、虚拟内存和虚拟CPU等,都是操作系统通过某种技术把少量的物理资源变成较物理资源多的逻辑资源,使共享资源的每个用户都感觉到自己独占了系统资源。

4.异步性

进程以不可预知的速度向前推进。内存中的每个程序何时执行、何时暂停、以怎样的速度向前推进,以及每道程序总共需要多少时间才能完成等,都是不可预知的。系统中什么时候会出现需要特殊处理的事件,如键盘中断、鼠标中断等也是随机的、不可预知的。现代操作系统需要很好地处理这些异步事件。

第四节 操作系统的功能

本节简单介绍操作系统的存储器管理、进程管理、设备管理和文件管理等功能,以及操作系统提供的用户接口。

一、内存管理

内存管理的主要任务是为多道程序的运行提供良好的环境,方便用户使用内存,提高内存的利用率,以及从逻辑上扩充内存以实现虚拟存储。为此,内存管理应具有内存分配、内存保护、地址映射和内存扩充功能。

1.内存分配

内存分配的主要任务是为每道程序分配内存空间,使它们各得其所。提高存储器的利用率,以减少不可用的内存空间。允许正在运行的程序申请附加的内存空间,以适应程序和数据动态增长的需要。

操作系统可以采用两种方式实现内存分配,即静态分配方式和动态分配方式。采用静态分配方式是把内存划分成固定大小和数量一定的区域,在系统运行过程中各分区的大小和数量不再变化。采用动态分配方式是系统在运行过程中,根据进程的请求分配内存,内存中分区的大小和数量都是动态变化的。

为了实现内存的分配,需要以下数据结构和功能支持。

1)用于内存分配数据结构。用来记录内存使用状况,如内存空闲区域的大小、空闲区域的起始地址等,为内存分配的实现提供依据。

2)内存分配功能。系统按照一定的内存分配算法分配内存空间。3)内存回收功能。系统需要回收被释放的内存空间。

2.内存保护

内存保护的任务:一是使操作系统内核的空间不会被用户随意访问,以保证系统的安全和稳定;二是确保每道用户程序都在自己的内存空间中运行,互不干扰。实现的方式可以采用界限寄存器存放允许程序访问的地址区间的上限和下限值。程序运行期间访何内存时,把访问地址与界限寄存器的值相比较,如果发生越界,便发出越界中断请求,以停止该程序的运行。需要说明的是,现代操作系统实现内存保护的方式不仅限于使用界限寄存器。

3.地址映射

CPU执行程序过程中访问内存时,需要把程序的逻辑地址转变为物理地址,这个转换的过程称为地址映射。下面首先介绍什么是逻辑地址和物理地址,然后解释地址映射的功能和过程。

(1)逻辑地址与物理地址

一个应用程序经编译后,通常会形成若干个目标程序,这些目标程序再经过链接而形成可装入程序。这些程序中指令和数据的地址都是相对于编译链接后的机器代码程序的起始地址计算的,由这些地址所形成的地址范围称为地址空间,其中的地址称为逻辑地址。如图1-4所示,一个main()函数经过编译后形成Intel指令集的目标文件中,程序第一条指令的地址为0,指令长度为1个字节。第二条指令的起始地址为1,指令长度为2个字节。第三条指令的起始地址为3,指令长度为5个字节。图1-5所示是经过链接后形成的可执行程序,第一条指令的起始地址不再是0,而是80483ec(用十六进制表示的地址)。图14和图1-5中的地址都是逻辑地址。在本书中,把所有非物理地址的其他各种形式的地址均称为逻辑地址。此外,由内存中的一系列单元所限定的地址范围称为内存空间,其中的地址称为物理地址,CPU访问内存需要将物理地址送入地址总线,以选中要访问的内存单元。

(2)地址映射

在多道程序系统中,地址空间中的逻辑地址和内存中的物理地址是不一致的。因此,存储器管理必须提供地址映射功能,以将逻辑地址转换为对应的物理地址。地址映射应在硬件的支持下完成。

编译程序把call B翻译成jump 0x01040这样一条跳转语句,意思是:调用函数B就是跳转到函数B的实现代码的起始处开始执行。函数B实现代码的起始地址是0x01040,编译器给出的这个地址不是物理地址,而是一个逻辑地址。当程序A执行到jump 0x01040指令时,系统必须通过内存管理的地址映射机制把逻辑地址0x01040转换成物理地址,将物理地址送到地址总线,才能访问到存放B的第一条指令的物理内存单元。

4.内存扩充

内存扩充的任务是借助于虚拟存储技术,从逻辑上扩充内存容量,使系统能够向用户提供比物理内存大的存储容量。为了能从逻辑上扩充内存,系统必须具有内存扩充机制,以实现下列功能。

1)请求调入功能。允许系统在装入一部分用户程序时就启动该程序的运行,在程序运行过程中若发现要执行的指令或要访问的数据尚未装入内存,通过请求调入将需要的指令或数据装入内存。

2)置换功能。在请求调入时,若发现内存空间不足,需要系统先将内存中的一部分内容换出到外存中,以便腾出内存空间装入当前需要的内容。

二、进程管理

进程可以被认为是程序的执行实体(进程的详细介绍见本书第二章)。进程管理功能主要包括进程的描述与组织、进程控制、进程同步、进程通信及进程调度。进程控制完成进程创建、撤销进程、唤醒进程和阻塞进程等操作。进程同步功能完成多个进程(含线程)运行的协调与互斥。进程通信功能用来实现进程之间的信息交换。进程调度功能是从多个可执行的进程中选出一个进程,把处理机分配给它。

三、设备管理

设备管理主要完成用户的I/O请求,为用户分配I/O设备。为了完成这些任务,设备管理应该具有以下功能。

1)缓冲管理。管理各种缓冲区。

2)设备分配。分配用户I/O所需要的设备。

3)设备处理。由设备驱动程序来实现CPU与设备控制之间的通信。

4)设备独立性和虚拟设备。设备独立性功能使应用程序独立于物理设备。例如,用高级程序设计语言编写打印图形的程序,与使用什么型号、品牌的打印机无关。虚拟设备的功能是把一个物理设备变换为多个对应的逻辑设备,使一个物理设备能供多个用户共享。

四、文件管理

1.文件存储空间的管理

为每个文件分配必要的外存空间,提高外存利用率,并能有助于提高访问文件的速度。

2.目录管理

为每个文件建立目录项并对众多目录项进行有效组织。目录项包括文件名、文件属性及

文件的地址等信息。

3.文件的读、写管理和存取控制

根据用户的请求,从外存中读取数据或将数据写入外存。防止未经核准的用户存取文件,防止冒名顶替存取文件,防止以不正确的方式使用文件。

五、提供用户接口

为了方便用户使用操作系统,操作系统向用户提供了用户与操作系统之间的接口。操作系统向最终用户提供命令行和图形用户接口,向程序员提供应用程序与操作系统之间的接口即系统调用。系统调用是操作系统实现的具有某种功能的程序模块,应用程序可以通过系统调用的接口使用操作系统实现的功能,获得操作系统内核的服务。

1.命令接口

为了便于用户与计算机系统的交互,早期的操作系统都向用户提供了命令接口。命令接口又可分为联机用户接口和脱机用户接口。

(1)联机用户接口

这是为联机用户设计的接口,它由一组键盘操作命令和命令解释程序组成。当用户在终端或控制台上每键入一条命令后,系统便立即转入命令解释程序,对该命令进行解释并执行该命令。在完成功能后,控制又回到终端或控制台上,等待用户键入下一条命令。

(2)脱机用户接口

脱机用户接口是为批处理作业的用户提供的,也称为批处理用户接口。

2.图形用户接口

20世纪90年代,在操作系统中开始引入图形化用户接口。在提供图形用户接口的操作系统中,用户可以轻松地通过选择窗口、菜单、对话框、滚动条、图标等简单的操作来完成对作业和任务的提交与控制。用户不必记住与操作对应的命令和命令参数的格式。图形用户接口使操作计算机成为相对简单的事情,也使更多的非专业人员能很快掌握计算机和应用程序的操作。

3.程序接口

操作系统提供给程序员的接口是系统调用。在类UNIX系统中,系统调用多使用C语言所提供的库函数。例如,在程序中,使用C的函数fseek(),而fseek()的代码调用了相应的系统调用。一般的操作系统都提供进程控制、文件操作、通信管理和系统维护等几类系统调用。关于系统调用的详细内容参见本书第二章第三节。

第五节 操作系统的体系结构

操作系统的体系结构是操作系统作为一种软件的体系结构,对操作系统的可靠性、灵活性和可移植性等方面都有重要影响。

一、软件体系结构简介

随着计算机硬件技术的飞速发展,应用领域日益广泛,软件的规模和复杂性不断增加。人们迫切需要一种新的超越传统算法和数据结构的高层抽象结构来描述整个系统,从而提出

了软件体系结构的概念。

软件体系结构是一个复杂软件系统的高层结构,为软件系统提供了一个结构、行为和属

性的高级抽象,包括系统元素的结构、元素间的相互关系,以及指导元素集成的模式和约束三个方面。它采用形式化的方法刻画了软件系统的组织和拓扑结构,显示了系统需求和构成系统的元素之间的对应关系,能够针对系统需求对软件的早期设计进行正确性和完整性分析,从而降低了开发后期产生错误的数量,减少了软件维护的成本,也提高了软件重用的抽象层次和粒度,对提高软件系统的质量和开发效率起着巨大的作用。总的来说,明确清晰的软件体系结构是一条贯穿软件系统整个生命周期的主线,是软件设计成功的基础和关键,也是对软件大型化、复杂化趋势的一种很好的应对决策。

二、操作系统体系结构的分析

操作系统体系结构研究整个操作系统内各组成成分,以及成分间和成分内部存在的相互关系。在操作系统的发展过程中,产生了许多不同类型的体系结构模型,它们各有其适用范围。

应用需求的变化和硬件体系结构的不断发展对操作系统的可靠性、可扩充性、可移植性及开放性都提出了更高的要求。嵌入式应用的发展要求操作系统具有更高的开发效率和较低的开发成本,这些变化必然要求修改和增强现有操作系统的结构。因此,深入理解和认识操作系统内核体系结构的实现模型,从而研究出更优越的操作系统体系结构和开发方法具有重要意义。本节详细介绍几种操作系统体系结构模型。

1.简单的监控程序模型

最初的计算机中并不存在操作系统这个概念,所有的任务都直接运行于硬件上,由程序员手工操作硬件系统。随着作业控制语言的出现,产生了简单的监控程序。这种系统的功能相当简陋,任意时刻系统中只能运行一个任务,这样保证了对系统信息的互斥访问,保护了系统数据的安全。但是这种设计的主要问题是系统缺乏“可伸缩性”,任务独占整个系统,这将极大地降低系统中潜在的并发性,从而使系统效率严重受损。在结构设计方面,没有任何结构方面的指导,整个系统的所有功能全部集中在一个单一模块中。后来的单体结构模型就是在此基础上发展起来的。这个阶段的典型代表是FMS(FORTRAN MonitorSystem)和 IB- SYS(在IBM 7094机上运行)。

2.单体结构模型

单体结构模型是软件工程出现以前的早期操作系统及目前一些小型操作系统采用的体系结构。在单体结构模型中,所有的软件和数据结构都放置在一个逻辑模块中,对外层的用户程序提供一个完整的内核界面-一系统调用。整个系统由若干具有一定独立功能的子程序组成,系统各部分之间没有确定的位置概念,彼此间没有信息隐藏,允许任一子程序调用其他子程序。因此,它的特点是结构简单,便于理解和实现,而且系统所有部分都集中在一个内核中,效率较高。缺点也很明显,由于各子程序间可以互相调用,系统结构关系复杂,容易引起循环调用和死锁。修改一个子程序往往会导致若干相关部分的变动,系统的可修改性和

可维护性比较差。图1-6所示为单体结构操作系统。

随着软件工程的提出和发展,借助于软件工程的模块化思想,内核开发人员根据功能的不同,可以将操作系统内核结构划分成不同的模块,模块间仅能通过各自定义良好的对外接

分层结构最经典的例子是Dijkstra的THE系统,它是20世纪60年代在TechnischeHoge- school Eindhoven上开发的。由于操作系统中各功能模块之间的调用关系是网状的,因此分层设计的思想有过度的局限性。要实现一个真正的分层操作系统是非常困难的,所以它难以被商用操作系统采用和推广,不过开发者在设计操作系统时可以借鉴分层的思想,使得系统在抽象层次上努力达到分层的目标。

4.客户/服务器模型与微内核结构

传统操作系统一般将所有功能模块放在内核模式中完成。随着计算机硬件体系结构的迅速发展,这种实现方式使得操作系统内核的结构变得非常复杂,代码量也迅速增加,这样系统代码的可扩展性、可移植性和可维护性越来越差,错误也随之增多。为了脱离这个困境,人们提出了微内核技术。

微内核技术是操作系统发展的一个里程碑,它产生了一种完全不同的操作系统体系结构,提供了操作系统发展的新途径。它的核心思想是核心功能外移,即把传统操作系统内核中的一些组成部分(如文件系统、网络和驱动程序等内核功能)放到内核之外作为一个独立的服务器进程来实现,在微内核中只保留了操作系统最基本的功能,包括处理机调度、存储管理和消息通信等,这些服务器借助于微内核传递消息来实现相互之间的交互。例如,当用户进程请求系统服务时,内核将用户的请求以消息的形式发送给相应的服务器进程,并将服务器进程返回的信息以消息的形式传送给用户进程。因此,微内核更多的是起着信息交换的作用:验证信息、在服务器间传递信息并授权访问硬件。

微内核结构用一个水平分层的结构代替了传统的纵向分层的结构,这样带来的好处是系统结构清晰,具有较高的灵活性、可靠性和可维护性:首先,只要接口规范,操作系统可以方便地增加或删除服务功能,系统具有很好的灵活性;其次,服务器进程运行在独立的用户进程空间中,如果某个服务器出现问题,不会引起系统其他服务器甚至是系统的崩溃,可靠性好;再者,微内核体积小,便于测试、管理和维护,而且修改服务器的代码也不会影响系统其他部分。另外,由于微内核技术实现了基于客户/服务器体系结构的操作系统,完全适宜于网络环境及分布式计算模型。

微内核技术是现代操作系统的一个发展趋势,结合面向对象设计方法,微内核技术具有更大的应用空间。目前微内核结构的操作系统主要向两个方向发展:一个是向通用操作系统的方向发展,主要代表是美国微软公司研制的WindowsNT操作系统和我国自行研制的COS- IXV2.3。另一个就是嵌入式操作系统,由于大多数嵌入式系统要求系统的规模比较小,而微内核结构正好满足这个需求,从而覆盖了几乎整个嵌入式系统的应用领域。典型代表是卡内基梅隆大学研制的Mach操作系统、WindRiver公司的Vxworks等。

5.动态可扩展结构模型

随着应用软件的日益丰富,传统操作系统结构阻碍了应用程序在特定领域方面的优化,为了获得高性能和高灵活性,从20世纪80年代人们就提出了动态可扩展结构模型。动态可扩展结构的基本思想就是在运行过程中,能够动态地实现系统行为扩展的结构,也可称之为弹性结构。

要具体实现动态可扩展结构,首先要解决的问题就是如何实现系统行为的动态改变,目前实现的方法就是通过动态地增删系统的代码,采用的主要技术有UPCALL 和 DOWNLOAD。 UPCALL技术就是指在微内核操作系统中通过核心层到用户层服务的调用方式来实现扩展的技术。由于微内核中的部分操作系统服务存在于用户层,用户可通过修改服务来获得不同的行为,但产生的后果是系统性能的下降。由此,人们又提出了外核结构模型,它试图将所有的传统操作系统内核中提供的抽象转移到用户空间,以操作系统库的形式提供服务,核心层只负责对物理设备的控制。应用程序可从用户层库中得到并控制内核抽象,从而实现了操作系统的动态扩展。这样系统具有很好的扩展性和灵活性。缺点是系统的安全性较低,内核抽象的安全必须由用户来保证,这也增加了用户的负担。这类结构的典型系统是MIT的Exo kernel 操作系统。

DOWNLOAD技术(也称为核心扩展技术)的核心思想就是将软件构件动态地下载到内核中,以达到改变操作系统行为的目的。该技术最大的难点就是系统安全问题。因为扩展程序是动态下载并组装到系统核心中的,因此不安全的程序有可能造成系统的故障甚至崩溃。当前这类系统主要采用软件保护机制进行保护。核心扩展技术是当前操作系统扩展性研究的主要方向。其中,典型代表有Harvard大学的VINO操作系统。

随着计算技术的发展和Internet与网络的普及及应用,产生了移动计算的需求,新的应用需求在一定程度上要求操作系统的动态可扩展性。因此,动态可扩展结构模型是适应当前应用变化的新一代操作系统体系结构模型,其应用前景十分广阔。

第六节 指令的执行

为了更好地理解操作系统原理的内容,在此对程序执行的本质及其与硬件、指令集的关系以一个简化的实例加以说明。程序是指令的集合,程序的执行就是按照某种控制流执行指令的过程。

1.指令周期

一个单一指令需要的处理称为指令周期,如图1-9所示,一个指令周期可以划分成两个步骤,分别是取指周期和执行周期。

2.取指令和执行指令

(1)取指令

在每个指令周期开始时,处理器从存储器中取一条指令。在典型的固定长度指令的处理器中,程序计数器(PC)保存有下一次要取的指令的地址。除非接收到别的指示,否则处理器在每次完成取指令操作后总是对PC递增,使它能够按顺序取得下一条指令,即位于下一个高端存储器地址的指令。

(2)执行指令

取到的指令被放置在处理器的指令寄存器IR中。指令中包含确定处理器将要采取动作的位,处理器解释指令并执行要求的动作,这些动作可分为4类。

1)处理器与存储器之间的指令或数据传送操作。2)处理器与I/O设备之间的指令或数据传送操作。3)算术运算操作或逻辑运算操作。

4)控制操作,即修改指令的执行顺序的操作。

3.一个实例

假设一台模型机,具备图1-10中列出的所有特征,处理器包含一个称为累加器(AC)的数据寄存器。所有指令和数据长度均为16位,故使用16位的单元或字来组织存储器。指令中用4位二进制位表示操作码,12位二进制位表示内存地址。因而最多可有16种不同的操作码,可直接访问的存储器大小为4096字节(用3位十六进制数表示)。

数部分的940。指令执行结果是把地址为940的内存单元的值3送入AC,第一条指令至此执

行完毕。此时AC中的值为3。

CPU根据当前PC指示的地址301,到内存单元301取要执行的第二条指令5941,然后

PC自动加1,变为302,指令5941放入IR。指令5941的操作码的二进制表示为0101,表示该指令执行的操作是把从存储器中取得的值与AC中的值相加,结果仍存放在AC中。执行结果是把地址为941的内存单元中的2取出,与当前AC中的3相加,结果5仍存放在AC中,第二条指令至此执行完毕。此时AC中的值为5。

CPU根据当前PC指示的地址302,到内存单元取要执行的第三条指令2941,然后PC自动加1,变为303。指令2941放入IR,解释该指令执行的结果是把当前AC中的值5送入地址为941 的内存单元。至此,各单条指令全部执行完毕,程序也执行完毕。

4.指令的执行小结

程序执行的过程是反复取指令和执行指令的过程。PC始终存有下一条待取指令的地址。指令执行的结果就是使寄存器或内存单元的值发生变化,指令执行的过程也就是存储体内容不断变化的过程。取指令和执行指令是由硬件完成的,不同硬件的体系结构支持不同的指令集合,为某一种硬件平台开发的操作系统不能直接在另一种体系结构的硬件上运行。任何高级程序设计语言的程序被编译成指令集合,其中的每一条指令属于计算机体系结构的指令集。

###########################################################################

第二章进程管理

操作系统本身就是一种软件,本质上就是数据结构加算法。所以,要掌握操作系统就要理解算法和实现算法所需要的数据结构。本章介绍操作系统最基本的概念、数据结构、算法和一些程序的控制流程。

操作系统中最核心的概念是进程,操作系统的其他所有内容都是围绕进程展开的。所以,在学习操作系统原理时,首先理解进程是必要的。本章将详细阐述进程的概念、进程的描述、进程的组织和进程的控制(包括进程的创建、撤销和进程状态的改变)。

本章为了使讲解原理不至于过于抽象,使用了一部分Linux程序的代码来帮助读者理解相关的原理,Linux内核代码仅作为辅助理解原理的实例,不作为考试内容,读者可根据代码的注释理解代码的流程,以达到理解原理的目的。

第一节 进程的描述

本节由程序的并发执行引人进程的定义,给出与进程有关的数据结构即进程控制块的作用和数据类型、进程状态,以及其在内核中的描述形式。

一、程序的并发执行

为了说明引入进程的原因,首先介绍程序的并发执行及程序并发执行的特点,而为了更好地理解程序的并发执行,本节先介绍程序的顺序执行,再对程序的并发执行与顺序执行进行比较,从而更好地理解程序并发执行的特点。

1.程序的顺序执行

早期无操作系统及单道批处理系统的计算机中,程序的执行方式都是典型的顺序执行。先进入内存的程序先执行,在一个程序执行完毕之前,不能执行其他程序。程序中的指令也是依照程序的控制流依次执行一条指令执行完毕之前不能开始执行另一条指令。程序顺序执行时具有以下特点。

(1)顺序性

处理机的操作,严格按照程序所规定的顺序执行,即只有前一操作结束后,才能执行后继操作。

(2)封闭性

程序是在封闭的环境下运行的。即程序在运行时独占全机资源,因而各资源的状态(除初始状态外)只有本程序才能改变。程序一旦开始运行,其结果不受外界因素的影响。

(3)可再现性

只要程序执行时的环境和初始条件相同,当程序多次重复执行时,其执行结果相同。例如一个求两个数之和的加法程序,其可再现性是指无论程序重复执行多少次,在输入的两个

加数相同的情况下,和不变,如1+1永远都等于2。

2.程序的并发执行

程序并发执行是指在同一时间间隔内运行多个程序。一个程序执行结束之前,可以运行其他程序。对用户而言,看到的是计算机同时运行多个程序。程序并发执行的确切含义是从宏观上,用户看到多个程序同时向前不间断地推进。而从微观上,任意时刻一个CPU上只有一个程序在执行。在现代单CPU或多CPU的计算机中,支持多任务及支持多用户多任务的操作系统都能够有效管理和支持程序的并发执行。多道程序系统和分时系统都允许用户程序在计算机系统中并发执行,程序并发执行具有以下几个特点。

(1)间断性

程序在并发执行时,由于它们共享资源,而资源数量又往往少于并发执行的程序数量,系统不能保证每个程序不受限制地占用资源。因而,每个程序在CPU上运行,都是时断时续的。当请求某种资源的程序数量大于被请求的资源数量时,就必然有因申请不到资源而暂停执行的程序。当其他程序释放资源后,该程序才可能继续执行。资源的有限使并发执行的程序呈现执行过程的间断性。

(2)失去封闭性

程序在并发执行时,由于它们共享资源或者合作完成同一项任务,系统的状态不再是只有正在执行的某一个程序可以“看见”和改变。

例如,有一个多用户的售票系统,各终端程序共享存储待售票数量的数据库表中的字段 X,任意第i个终端程序设置自己的局部临时变量Ri,采用下列程序可实施卖票管理。

(3)不可再现性

程序在并发执行时,由于失去了封闭性,也将导致其失去执行结果的可再现性。同一个程序在输入完全相同的情况下多次运行,可能出现不同的运行结果。

下面为程序并发执行结果不可再现的示例。

用高级程序设计语言表达的程序语句counter = counter+1,经过编译后转化为多条指令以完成其功能,CPU执行的指令单位是编译后的机器语言指令,而不是高级语言的一条语句。

用r1、r2 表示两个通用寄存器,counter = counter+1经编译后细化为以下形式的基本指令序列。

二、进程的概念

当操作系统支持程序并发执行时,并发执行的程序可能是同一个程序在不同数据集合上的执行,也可能是不同的程序在不同数据集合上的执行,它们共享系统资源。用程序已不能描述程序的并发执行,所以引入了进程的概念。

1.进程的定义

定义1:进程是允许并发执行的程序在某个数据集合上的运行过程。

定义2:进程是由正文段、用户数据段及进程控制块共同组成的执行环境。正

文段存放被执行的机器指令,用户数据段存放进程在执行时直接进行操作的用户数据。进程控制块存放程序的运行环境,操作系统通过这些数据描述和管理进程。

程序装入内存后就可以运行了,根据指令计数器PC的值,不断将指令从内存取到CPU的指令寄存器中,经过译码后完成各种操作。这些指令控制的对象不外乎各种存储器(内存、外存和各种CPU寄存器),这些存储器中有待运行的指令和待处理的数据,指令只有得到PU才能发挥其作用。可见,在计算机内部,程序的执行过程实际上对应了一个执行环境的总和。这个执行环境包括程序中的各种指令和数据,还有一些额外数据,如寄存器的值、用来保存临时数据的堆栈、被打开文件的数量及输入/输出设备的状态等。这个执行环境的动态变化表征程序的运行,一个进程对应了一个这样的环境。进程代表了程序的执行过程,是一个动态的实体,它随着程序中指令的执行而不断变化,在某个特定时刻的进程内容被称为进程映像。

2. 进程的特征

进程是操作系统管理的实体,对应了程序的执行过程,具有以下几个特征。

1)并发性。多个进程实体能在一段时间间隔内同时运行。并发性是进程和现代操作系统的重要特征。

2)动态性。进程是进程实体的执行过程。进程的动态性表现在因执行程序而创建进程、因获得CPU而执行进程的指令、因运行终止而被撤销的动态变化过程。此外,进程在被创建后还有进程状态的变化。

3)独立性。在没有引入线程概念的操作系统中,进程是独立运行和资源调度的基本单位。

4)异步性。是指进程的执行时断时续,进程什么时候执行、什么时候暂停都无法预知,呈现一种随机的特性。在中断技术出现以后,系统还需要处理随时可能出现的中断事件。

5)结构特征。进程实体包括用户正文段、用户数据段和进程控制块。

3.进程与程序的比较

(1)进程与程序的区别

程序是静态的,进程是动态的。程序是存储在某种介质上的二进制代码,进程对应了程序执行的过程,系统不需要为一个不执行的程序创建进程,一旦进程被创建,就处于不断变化的动态过程中,对应了一个不断变化的上下文环境。

程序是永久的,进程是暂时存在的。程序的永久性是相对于进程而言的,只要程序的拥有者不去删除它,程序可以永久地存在于磁盘、U盘等外存储介质中。进程因程序的执行而被创建,因程序执行的结束而被撤销,有一个相对短暂的生命期。

程序与进程的存在实体不同。程序是指令的集合,而进程是包括了正文段、用户数据段和进程控制块的实体。

(2)进程与程序的联系

进程是程序的一次执行,进程总是对应至少一个特定的程序,执行程序的代码。

一个程序可以对应多个进程。同一个程序可以在不同的数据集合上运行,因而构成若干个不同的进程。几个进程能并发地执行相同的程序代码,而同一个进程能顺序地执行几个程序。

《现代操作系统》的作者AndrewS.Tanenbaum在其著作中对进程和程序的关系给出了一段很形象的比喻:“一位计算机科学家正在为她的女儿烘制生日蛋糕。他有做蛋糕的食谱,以及做蛋糕的各种原料,如面粉、鸡蛋、糖和香草汁等。做蛋糕的食谱好比是程序,计算机科学家好比是处理器CPU,而做蛋糕的各种原料就是输入数据。进程就是计算机科学家阅读食谱利用原料烘制蛋糕的过程。”

三、进程控制块

操作系统中的进程不仅是一个概念,而且是真实存在的实体。应用程序对应的进程由程序、用户数据和操作系统管理进程所需要的进程控制块构成。进程实体存在的标志是操作系统管理进程所使用的数据结构进程控制块。

1.什么是进程控制块(ProcessControl Block,PCB)

进程控制块是进程实体的一部分,是操作系统中最重要的数据结构。进程控制块中记录了操作系统所需要的、用于描述进程情况及控制进程运行所需的全部信息。

在使用C语言实现的操作系统中,这个数据结构是一个结构类型的变量。该结构类型中包含描述和管理进程需要的字段,这些字段的类型可以是简单类型,也可以是复杂类型操作系统在创建进程时,首先要为进程创建进程控制块,也就是生成一个进程控制块类型的变量,以存储所创建进程的描述信息。每个进程有唯一的进程控制块,进程控制块是操作系统感知进程存在的唯一标志。下面是Linux2.6.11的进程控制块结构的定义和其中的部分字段。

2.进程控制块中的信息

不同操作系统进程控制块中包含的描述信息不完全相同,一般操作系统中的进程控制块中通常包含以下信息。

(1)进程标识符信息

进程标识符用于唯一标识一个进程。进程控制块中除了存有本进程的标识符外,还存放其父进程、子进程的标识符。

(2)处理机状态信息

处理机是被进程共享的资源,当一个进程在CPU上执行时,CPU寄存器的值随进程的执行不断变化,当发生进程切换时,当前的进程执行要被暂停,新进程占用CPU。为了使当前进程的CPU值不被新进程覆盖而丢失,必须将当前进程的CPU寄存器值保存到内存中,以便该进程再次获得CPU时,能从内存中加载寄存器的值,恢复进程上次被暂停时的CPU环境,使进程从上次被中断处继续执行。进程控制块中保留的处理机状态信

息通常包括以下几个。

1)通用寄存器。用户程序可以访问的寄存器,用于暂存信息。

2)指令计数器。其中存放了CPU要访问的下一条指令的地址。

3)程序状态字PSW。其中包含状态信息,如条件码、执行方式和中断屏蔽标志等。

4)用户栈指针。每个用户进程都有一个与之相关的系统栈,用于存放过程和系统调用参数及调用地址,栈指针指向该栈的栈顶。

(3)进程调度信息

进程调度信息包括进程状态信息、进程优先级和进程调度所需的其他信息。

(4)进程控制信息

进程控制信息包括程序和数据的地址、进程同步和通信机制、资源清单,以及链接指针。

本书中的数据结构就是为程序的需要而定义的简单类型或复杂类型的变量,变量用来存放随着程序的执行不断发生变化的数据。进程控制块是复杂类型的变量。

操作系统如何利用进程控制块?换句话说,进程控制块这种数据结构在操作系统这种复杂的软件中有什么作用呢?下面以Linux的进程控制块结构中的变量为例来说明该问题。

例2-2:进程控制块 task_struct的prio字段,用来存放进程的优先权。在操作系统决定为系统中的多个可执行进程中的哪个进程分配资源时,可以利用这个字段来比较进程的优先权,把资源分配给prio字段值最大或最小的进程。

四、进程的状态

进程控制块的状态字段描述了进程当前所处的状态。它由一组标志组成,其中每个标志描述一种可能的进程状态。Linux中进程状态字段是task_struct中的 state字段。

不同操作系统在设计和实现时,定义的进程状态数量和含义有所不同,不同版本的 Windows、UNIX和Linux的进程状态数都不同,对每种状态的定义也不同。为了说明操作系统实现的原理,可以把操作系统的进程状态归结为几种基本的状态,而不影响对操作系统基本实现原理的解析。

1.进程的3 种基本状态

(1)就绪态

就绪态是进程一旦获得CPU就可以投人运行的状态。在多任务系统中,可以有多个处于就绪态的进程,这些进程被组织成一个或多个就绪进程队列。

Linux2.4把所有就绪进程组织成一个先进先出的就绪队列,Linux2.6.11根据进程的优先权不同将就绪进程组织成多个不同的就绪队列。优先权相同的进程放在同一个就绪队列中,每个不同的优先权对应不同的就绪队列。

(2)执行态

执行态是进程获得CPU正在运行的状态。系统中执行态的进程数量受CPU数量的限制。单CPU系统中,任意时刻只能有一个进程处于执行态。有N个CPU的多CPU系统中,任意时刻系统中最多有N个进程处于执行态。

(3)阻塞态

阻塞态是进程由于等待资源或某个事件的发生而暂停执行的状态,系统不会为处于阻塞态的进程分配CPU。阻塞态进程在获得其等待的资源或其等待的事件发生之后,转变为就绪态。处于阻塞态的进程数量可能很多,系统可以根据不同的阻塞原因将进程组织成不同的阻塞队列。例如,将因为等待打印机而阻塞的进程排列成一个打印阻塞队列,将等待输人数据的进程排列成等待输入数据的队列。

第二节 进程的控制

一、进程的创建

创建新进程包括为进程分配必要的资源,建立操作系统用于管理进程的数据结构(如进程控制块)等操作。通常在下列情况下需要创建新进程。

1)用户登录。在交互式系统中,当一个新用户登录系统时会创建进程。

2)作业调度。当把位于外存储器中的作业调入内存准备运行时,操作系统会为作业的运行创建进程。

3)提供服务。操作系统可以创建一个进程,代表用户程序执行某种功能,使用户无需等待。例如,用户请求打印一个文件,操作系统可以创建一个管理打印的进程,进而可以使请求进程继续执行,与完成打印任务的时间无关。

4)应用请求。当用户发出执行某程序的命令,或者用户程序在执行中基于并行的要求在程序中显式调用进程创建的系统调用时,都会引起进程的创建。

在Linux系统中,除了0号进程(swapper进程)外的其他进程都是由其父进程创建的。在操作系统启动并正常工作后,系统中的已有进程在执行过程中都可以通过系统调用创建新进程。被创建的新进程成为创建该新进程的进程的子进程,创建者进程和被创建进程成为父子进程。一个进程可以创建多个子进程,由同一个进程创建的多个子进程之间的关系称为兄弟进程。系统中所有的进程通过父子关系和兄弟关系被组织成一棵进程树,如图2-5所示。

调用创建新进程的系统调用来创建进程的一般步骤如下。

1)申请空白 PCB。

2)为新进程分配资源。

3)初始化进程控制块。

4)将新进程插入就绪队列。

Linux2.6.11中创建进程的常用系统调用在函数库中的接口函数是fork()。

下面以一般用户进程的创建为例说明进程创建的过程。用户在shell中输入命令后,

shell 大多数情况下调用函数fork()来创建进程。

在Linux内核文件linux/include/asm - x86_64/unistd.h中定义其系统调用号。

函数fork对应的系统调用是在/linux+v2.6. 11/arch/i386/kernel/process.c中定义的sys_ fork,在这个系统调用中调用内核函数do_fork( ),由do_fork( )完成进程创建。简单而言, do_fork( )主要完成下列功能。

1)为新进程分配唯一的进程pid。

2)为新进程获取自己的进程描述符。

3)为新进程指定内存地址空间。4)完成进程的一些初始化工作。

5) 返回进程的pid。

Linux创建进程的系统调用还有clone和vfork,它们对应的系统调用例程分别是sys_ clone 和sys_vfork。这两个系统调用在/linux2.6.11/arch/i386/kernel/process.c中定义,都调用了do_fork 函数。

与进程创建密切相关的函数还有execve(),与其对应的系统调用是sys_execve( ),主要功能是使进程执行新的程序代码。

二、进程的阻塞

操作系统在下列情况下可能进行进程的阻塞和唤醒操作。

1)请求系统服务。例如打印服务,进程在提出打印请求后,系统创建打印服务进程为该进程服务,而提出打印请求的进程可能被阻塞起来等待打印的完成。

2)启动某种操作。例如,进程发出启动I/O或启动打印机的命令后,等待启动完成时处于阻塞态。

3)新数据尚未到达。对于一个计算进程,如果新的输入数据还没有到达,计算进程需要阻塞等待。

4)无新工作可做。发送消息之后等待时。完成进程阻塞的简化过程如下。 I)将进程的状态改为阻塞态。2)将进程插人相应的阻塞队列。

3)转进程调度程序,从就绪进程中选择进程为其分配 CPU。

处于执行态的进程被阻塞后,CPU空闲,需要执行进程调度程序,从就绪态进程中为

CPU选择一个进程运行。

三、进程的唤醒

操作系统通过下列过程将阻塞态进程唤醒,使其变成就绪态进程。进程唤醒的过程如下。

1)将进程从阻塞队列中移出。

2)将进程状态由阻塞态改为就绪态。3)将进程插入就绪队列。

四、进程的终止

进程的终止也称进程的撤销,在下列情况下,进程会被终止。

1)当进程正常执行完毕,调用终止进程的系统调用,请求操作系统删除该进程。

2)一个进程调用适当的系统调用,终止另外一个进程。通常,操作系统规定只允许父进程通过这种方式终止其子进程。

父进程终止其子进程的原因可能有以下几个。

1)子进程使用了超过它所分配到的一些资源。

2)分配给子进程的任务已不再需要。

3)父进程退出,如果父进程终止,那么操作系统不允许子进程继续。对于这类系统,如果一个进程终止,那么它的所有子进程也被终止。这种现象称为级联终止,通常是由操作系统进行的。在UNIX系统中,如果父进程终止,那么其他所有子进程会以init进程作为它们新的父进程。因此,子进程仍然有父进程可以收集它们的状态和执行统计。

操作系统通过系统调用完成进程终止的一般过程如下。

1)从进程PCB中读进程状态。

2)若进程正在执行,则终止进程的执行。

3)若进程有子孙进程,在大多数情况下需要终止子孙进程。4)释放资源。

5)将终止进程的 PCB移出。

五、操作系统的启动和系统中进程的出现

当打开计算机电源后,计算机会先进行加电自检,然后寻找启动盘。如果是选择硬盘启动,计算机会检查硬盘的0柱面0磁道1扇区。如果发现该扇区以0xAA55结束,则BIOS认为它是引导扇区,一旦发现引导扇区,BIOS会执行程序将其装人到内存地址0000:7c00处,然后跳转到该地址处执行这段引导程序代码,开始加载操作系统。

当硬盘被划分为多个分区,同时安装了多个操作系统时,每个分区都有自己的引导扇区,但是整个硬盘有一个主引导扇区,主引导扇区就是硬盘的0柱面0磁道1扇区。通过执行主引导扇区的代码,判断当前被激活的分区,然后加载被激活分区的引导扇区,通过该引导扇区代码的执行加载该激活分区的操作系统。

Linux系统从硬盘引导、加载、初始化和创建进程的简化过程如图2-6所示。

1.支撑功能

支撑功能包括中断处理、时钟管理和原语操作。原语操作也称原子操作,是一组在执行过程中不能被中断的操作。

2. 资源管理功能

资源管理包括进程管理、存储器管理和设备管理。

本节主要介绍操作系统在完成中断处理、时钟管理中的作用,以及操作系统内核的构成部分-系统调用。

一、中断

1.什么是中断

中断是改变处理器执行指令顺序的一种事件,这样的事件与CPU芯片内外部硬件电路产生的电信号相对应。

计算机在执行程序的过程中,当出现中断时,计算机停止现行程序的运行,转向对这些中断事件的处理,处理结束后再返回到现行程序的间断处。

2.为什么需要中断

引入中断机制后,使CPU可以与其他设备并行工作,能有效提高CPU的利用率,改善系统性能,支持系统的异步性。引入中断机制前,当在CPU上执行的程序遇到I/O时, CPU采取反复轮询的方式,检测本次I/O是否结束。在轮询的过程中,CPU不能完成任何更有效的工作。引入中断机制后,一个正在执行的进程p1请求I/O后,CPU启动这次的 I/O,然后,在具体设备为pl的I/O服务的过程中,CPU可以先去执行其他进程。其间, CPU 与进程p1的I/O是并行工作的。在本次I/0完成后,通过中断机制使CPU获得进程I/0 结束的信息,转中断处理。中断处理完毕再返回到原来进程pl的断点处,继续执行后续指令,或者使p1变为就绪态进程,CPU执行其他进程。以目

图2-7表示了在引入中断处理机制的系统中,打印服务进程与其他进程并发执行、打印机与CPU并行工作的情况。

从图 2-7可见,在打印机准备的过程中,CPU与打印机是并行工作的。在打印机接收完打印数据、进行打印的过程中,打印机与CPU也是并行工作的。

3.中断的类型

中断分为同步中断(也称内部中断或异常)和异步中断(也称外部中断)两种。

(1)同步中断(内部中断或异常) 同步中断是当指令执行时由CPU控制单元产生的,之所以称为同步,是因为只有在一

条指令终止执行(注意:此时指令并不一定已经执行完毕)后CPU才会发出中断,如除法出

错、调试、溢出和浮点出错等。

异步中断是由其他硬件设备随机产生的。在Intel微处理器手册中,把同步中断和异步

(2)异步中断(外部中断)

中断分别称为异常(Exception)和中断(Interrupt)。Linux中采用这种分类,有时也用术语“中断信号”来表示这两种类型的中断(同步中断及异步中断)。

外部中断又可以分为外部可屏蔽中断和外部不可屏蔽中断。

1)外部可屏蔽中断。外部可屏蔽中断是由I/O设备产生的中断,有两种方式可以屏蔽中断。一是如在Intel80x86的CPU上,把EFLAGS寄存器的IF标志置0,表示关中断。此时,CPU忽略所有可屏蔽中断。二是可以对可编程中断控制器(ProgrammableInterrupt Con- troller,PIC)编程来禁止中断请求(InterruptRequest,IRQ)。也就是说,可以告诉PIC停止对给定的IRQ线发布中断。

2)外部不可屏蔽中断。外部不可屏蔽中断是由紧急事件引起的中断,如硬件故障。

4.引起中断的原因

引起中断的原因可能有以下几个。

1)人为设置中断。在程序中人为设置中断。

2)程序性事故。例如,计算中出现除数为0。

3)硬件故障。插件接触不良、电源掉电等。

4)I/O设备。I/O设备被启动以后,一旦其准备就绪或完成一次输入/输出,便向CPU发出中断请求。

5)外部事件。如用户通过键盘和鼠标来中断现行程序。

5.中断响应

(1)响应中断的条件

对于可屏蔽中断,开中断是响应中断的前提。例如,在Intel80x86CPU上,当EFLAGS寄存器的IF标志置1表示开中断。

(2)响应中断的时机

对于外部中断,CPU每执行完一条指令都会检测是否有外部中断信号的到来。若有,则转中断处理过程。

6.单重中断的处理过程

下面以单重中断为例,简单说明外部中断处理的过程。假定在中断处理的过程中不再响应新近产生的中断信号,直到本次中断处理完毕。同时假定中断处理完毕后,CPU返回被

中断的程序断点处继续执行被中断的程序。

外部中断的处理过程如图2-8所示。CPU在反复执行指令的过程中,每执行完一条指令,都会检测是否有外部中断信号的到来。如果检测到有中断信号,则转中断处理过程。

1)系统关闭中断,保护断点,把当前要执行的下一条指令的地址保存到内存中,以便中断返回时,能把这个地址恢复到程序计数器PC中,使被中断的程序从断点处开始继续执行。

2)转中断处理程序。在中断处理程序中完成保护现场的工作,就是把相关的硬件上下文信息保存到内存中。硬件上下文就是中断返回恢复被中断程序的执行时,需要写回CPU寄存器的值。

3)保护完现场后,要根据中断向量到中断向量表中(在Linux中是到中断描述符表中)找到与中断处理子例程入口地址相关的信息,由这些信息得到中断处理子例程的入口地址,以执行中断处理子例程,完成本次中断处理的特定处理工作。

4)最后,恢复现场,开中断,CPU返回断点处继续执行被中断的程序。

7. 如何找到中断服务子程序

下面以Intel 80x86和Linux系统为例说明获取特定中断(键盘、鼠标和时钟中断等)服务子程序入口地址的原理。

二、时钟管理

1.时钟的重要性

时钟是计算机系统的脉搏。计算机的很多活动都是由定时测量(Timing Measurement )来驱动的。计算机系统的定时测量功能对用户通常是不可见的。例如,屏幕保护功能的实现就利用了定时器。操作系统的内核跟踪用户最后一次按键或移动鼠标后经过了多少时间,如果这个时间达到一个用户设定的阈值,屏幕会自动进入被保护状态。

编译系统为了缩短一个比较大的工程文件重新编译和链接的时间,对于一个工程文件中的所有源程序,并不是每次修改某一个源文件后都需要重新编译所有的源文件。通常只编译那些源文件的最后修改时间晚于相应目标文件生成时间的源程序。例如,有一个文件ac和它的目标文件a.obj,如果ac的生成时间晚于a.obj的生成时间,需要重新编译ac以形成新的aobj。为了进行这些操作,程序必须能从每个文件中检索到文件的最后修改时间,即时间戳(Timestamp)。因此,这样的时间标记必须由内核自动设置。

更重要的是,操作系统的内核可以利用时钟机制防止一个进程垄断CPU或其他资源。系统可以利用时钟机制限制一个用户进程在CPU上连续执行的时间,当进程一次连续运行的时间超过限定的时间时,由系统将CPU分配给其他进程。

计算机中当前时间显示功能、即时通信程序等与时间相关的软件都需要时钟机制的支持。

2.计算机系统中的时钟

大部分PC中有两个时钟源,分别称为实时时钟(Real TimerClocker,RTC)和OS时钟。 RTC时钟也称CMOS时钟,是一块时钟芯片,靠电池供电,为计算机提供计时标准,是最原始、最底层的数据。OS时钟产生于PC主板上的定时/计数芯片,在开机时有效,由操作系统控制。

计算机开机加电后,操作系统通过BIOS获取当前RTC时钟的值作为系统的初始时间,操作系统初始化后启用自己的时钟硬件,即可编程间隔定时器(Programmable Internal Timer, PIT)。PIT可以按照一定的频率产生时钟中断(TimerInterrupt),以告知内核又一个时间间隔过去了。

RTC时钟、OS 时钟和应用程序之间的关系如图2-11所示。

3.操作系统的时钟机制

操作系统内核需要完成两种主要的定时测量,一是保存当前的日期和时间,以便能通过系统调用把它们返回给用户程序,让用户程序获得当前的日期和时间,也可以由内核本身把当前时间作为文件和网络包的时间戳。二是维持定时器,这种机制能够告诉内核或用户程序某一时间间隔已经过去了。

操作系统依靠时钟硬件(可编程间隔定时器PIT)和时钟驱动程序完成上述两种定时测量功能。

(1)OS时钟管理硬件(可编程间隔定时器PIT)

可编程间隔定时器的功能是按指定的时间间隔产生时钟中断,测量逝去的时间,并触发与时间有关的操作。主要由3部分构成:晶振、计数器和保持寄存器,如图2-12所示。

晶振能够产生固定频率的脉冲,每产生一次脉冲,计数器的值减1,当计数器的值减为0时,产生一次时钟中断信号,保持寄存器的值再次送计数器。由

可编程间隔定时器产生的时钟中断信号送到可编程中断控制器的时钟中断信号引脚上。

可编程间隔定时器产生时钟中断的过程如图2-13所示。

(2)时钟软件--时钟驱动程序 时钟驱动程序也称为时钟中断处理程序,每产生一次时钟中断信号,操作系统内核要执行时钟驱动程序,时钟驱动程序完成下列功能。

三、系统调用

1.什么是系统调用

系统调用是一群预先定义好的模块,它们提供一条管道让应用程序或一般用户能由此得到核心程序的服务。系统调用是系统程序与用户程序之间的接口,在类UNIX系统中,系统调用多使用C语言提供的库函数作为接口。例如,在Linux操作系统中使用C语言编程,在程序中使用C的函数getpid()以获取进程的内部标识符,而getpid()的代码调用了在系统态运行的系统调用sys-getpid( )。

2.系统调用与一般函数的区别

为了说明系统调用与一般函数的区别,先说明什么是用户态执行,什么是系统态执行。

(1)用户态执行

用户空间是指用户进程所处的地址空间,一个用户进程不能访问其他进程的用户空间,只有系统程序才能访问其他用户空间。当CPU执行用户空间的代码时,称该进程在用户态执行。

(2)系统态执行

系统空间是指含有一切系统核心代码的地址空间,当CPU执行系统核心代码时,称进程处于系统态执行。

系统调用与一般函数调用的区别如下。

1)系统调用运行在系统态(核心态),而一般函数运行在用户态。

2)系统调用与一般函数调用的执行过程不同。系统调用执行时,当前进程被中断,由系统找相应的系统调用子程序,并在系统态下执行,执行结果返回进程。

3)系统调用要进行“中断处理”,比一般函数调用多了一些系统开销。

这段代码看起来很简单,先执行movl$__NR_getpid,% eax,把系统调用号__NR_getpid保存到eax 寄存器中,以便将来给内核程序使用。因为内核实现了很多不同的系统调用,所以进程必须传递一个名为系统调用号的参数来识别所需的系统调用。系统调用号是一个整数,与系统调用一一对应。__NR_getpid是getpid()的系统调用号。内核需要根据_NR_get- pid 来找到与 getpid()对应的系统调用实现程序sys_getpid。

然后执行int$0x80,使进程进入内核态,并转去执行与0x80中断对应的处理程序sys- tem_call。最后通过执行movl % eax,__Res,将系统调用结果返回给用户。

从图2-15中可以看到,在进程处于系统态执行system_call的过程中,利用getpid()的系统调用号_NR_getpid找到getpid()对应的系统调用实现程序sys_getpid,然后执行sys_ getpid 获得当前进程的内部标识符,最后将程序返回到用户态。

为了把系统调用号与相应的系统调用实现程序关联起来,Linux内核利用了一个系统调用分派表(Dispatch Table)。这个表存放在sys_call_table数组中,有NR_syscalls个表项(在 Linux 2.6.11内核中这个值是289)。系统调用分派表的第n个表项包含系统调用号为n的系统调用实现程序的地址。getpid()对应的系统调用号是_NR_getpid,所以在系统调用分派表的第_NR_getpid个表项中存有sys_getpid程序的起始地址。

5.系统调用的类型

根据系统调用的功能把系统调用总结为以下几种类型。

1)进程控制类系统调用。创建、撤销进程;获得、改变进程属性。

2)文件操纵类系统调用。创建文件、删除文件、打开文件、关闭文件和读/写文件。

3)设备管理类系统调用。请求、释放设备。

4)通信类系统调用。打开、关闭连接,交换信息。

5)信息维护类系统调用。返回系统当前日期、时间、版本号、用户数、空闲内存和磁盘空间大小等信息。

6.Linux 中的系统调用举例

1)fork 创建一个新进程。

2)clone 按指定条件创建子进程。

3) execve 运行可执行文件。

4)exit 中止进程。_exit立即中止当前进程getdtablesize所能打开的最大文件数。

5)getpgid获取指定进程组标识号。

6)open 打开文件。

7)creal 创建新文件。

8)close关闭文件描述字。

9) read 读文件。

10) write写文件。

7.操作系统提供系统调用的优点

1)使编程更加容易,把用户从学习硬件设备的低级编程特性中解放出来。

2)极大地提高了系统的安全性。

第四节 进程同步

多任务操作系统支持多个进程并发执行,并发执行的进程共享系统的软件和硬件资源。进程访问资源是通过执行程序指令实现的,在这种情况下,操作系统可以也必须对进程访问共享资源的过程进行控制和管理。否则,系统会出现程序运行结果的错误。操作系统同步机制的主要任务就是要保证在多任务共享系统资源的情况下,程序执行能得到正确的结果。此外,有些进程之间具有相互合作关系,同步机制需要解决这些进程执行的协调问题。

一、进程同步的基本概念

在多道程序环境下,进程之间可能存在资源共享关系和相互合作关系。进程同步有两个任务,一是对具有资源共享关系的进程,保证诸进程以互斥的方式访问临界资源。临界资源是必须以互斥方式访问的共享资源。二是对具有相互合作关系的进程,保证相互合作的诸进程协调执行。相互合作的进程可能同时存在资源共享的关系。

为了说明什么是临界资源,先回忆前面p1、p2两个进程并发执行,counter是全局变量,初始值为0,p!、p2两个进程分别对counter做加1操作,代码如下。

counter = register2 //执行结果:counter=1

执行结果是counter=I,而正确结果应该是counter =2。

如果p1和p2以互斥的方式去访问counter,也就是说,如果p1先开始对counter的访问,p2 就必须等待p1对counter的访问完全结束,再开始对counter的访问。反之,如果p2先开始对counter 的访问,p1就必须等待p2对counter的访问完全结束,再开始对counter的访问。那么p1和p2对counter访问指令的交错执行的情况就不会出现,计算结果的错误也就不会出现了。pI和p2以互斥的方式去访问counter的含义是在p1和p2中的任意一个进程执行counter+1操作的一系列指令的过程中,不允许另一个进程执行访问counter的操作。类似counter这样必须以互斥方式访问的共享资源称为临界资源。

在设计操作系统时,设计人员必须严格界定系统中的哪些资源是临界资源,通过同步机制保证系统运行过程中,对临界资源的访问进行有效控制。

临界区是进程中访问临界资源的那段代码。访问临界资源是通过执行临界区代码来实现的,如果能使程序以互斥的方式进入临界区,就能够实现对临界资源的互斥访问。这一点可以通过在临界区前面加进入区代码,在临界区后面加退出区代码来实现。进入区代码在临界区代码之前执行,检查进程是否可以进入临界区并对临界区“加锁”。退出区代码在临界区代码之后执行,完成释放临界区访问权的功能。

在进程中,可以采用下列模式的代码来实现对临界资源的互斥访问。

二、同步机制应遵循的准则

当存在多种可选的同步方案时,可能是硬件或软件的不同,也可能是算法的不同,根据什么来权衡利弊,做出恰当的选择呢?对于一种同步技术,如何对它的正确性和性能做出评价呢?同步机制应遵循的准则可以为人们提供判断、选择和评价的参考依据。

1.空闲让进

当没有进程处于临界区时,表明临界资源处于空闲状态,应允许一个请求进入临界区的进程立即进入自己的临界区,以有效地利用临界资源。

2.忙则等待

当已有进程进人临界区时,表明临界资源正在被访问,因而其他试图进入临界区的进程必须等待,以保证对临界资源的互斥访问。

3.有限等待

对要求访问临界资源的进程,应保证在有限时间内能进入自己的临界区,以免进程陷入无限等待的状态。

4.让权等待

当进程申请不到共享资源的访问权时,应立即释放处理机,以免进程陷人“忙等”状态,浪费CPU资源。

三、信号量机制

在信号量机制中,用某种类型的变量,即信号量的取值来表示资源的使用状况,或某种事件是否发生,以此为基础实现进程的同步。本节将介绍整型信号量机制、记录型信号量机制、AND型信号量机制。

交通信号灯的作用是通过灯的不同颜色告知车辆应如何行驶,信号量机制类似这种信号灯的作用。对不同的共享资源设置被称为信号量的变量,用信号量的取值来表示资源的使用状况,或某种事件是否发生。通过信号量的取值来判断进程是否能访问与信号量对应的共享资源。

1.整型信号量机制

整型信号量是表示共享资源状态且只能由特殊的原子操作改变的整型量。其完成同步功能的原理是定义一个整型变量,用整型变量值来标记资源的使用情况。如果整型量>0,说明有可用资源;如果整型量≤0,说明资源忙,进程必须等待。对于一次只允许一个进程访问的临界资源,可定义一个用于互斥的整型信号量,并将其初始化为1。整型信号量的值只能通过两个特定的原子操作wait和signal来改变。

假定p1 进程先执行对counter的访问。因为在进入临界区counter = counter +1前,p1必须先执行wait( mutex )操作。而mutex此时的值为1,所以while mutex≤0 do no - op中的 while 条件不满足,while循环结束,执行mutex =mutex-1操作。结果信号量mutex的值为0。pl 在结束counter = counter +1和signal( mutex)操作之前,如果p2也试图进入临界区执行 counter = counter +1,由于p2在进入临界区代码前必须先执行wait(mutex)操作,而此时mu- tex =0,进程p2的 wait( mutex )操作中的while mutex≤0 do no - op 的 while条件满足,进程 p2只能执行while循环中的空操作,无法进入自己的临界区。只有当p1执行完临界区代码,并通过执行signal( mutex)操作,完成mutex = mutex +1,使 mutex=1后,当CPU再次执行 p2时,才会由于p2 执行的while mutex≤0 do no - op中的while条件不满足,而结束循环。 p2 执行完 wait( mutex)的最后一条语句mutex = mutex -1后,得以进入自己的临界区执行 counter = counter +1。

对于任意进程p,要访问临界资源CS,如果与CS对应的整型信号量设置为mutex,mu- tex初值为1,以如下形式在进程中添加同步代码可以实现进程对CS的互斥访问。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值