【专题】进程的描述与控制

发布于:2024-10-15 ⋅ 阅读:(75) ⋅ 点赞:(0)

1. 前趋图和程序执行

1.1 前趋图

前趋图,是指一个有向无循环图,可记为DAG,它用于描述进程之间执行的先后顺序。

  • 图中的每个结点可用来表示一个进程或程序段,乃至一条语句;

  • 结点间的有向边则表示两个结点之间存在的偏序或前趋关系。

进程(或程序)之间的前趋关系可用“”来表示,如果进程Pi和Pj存在着前趋关系,可表示为(Pi,Pj)∈→,也可写成Pi→Pj,表示在Pj开始执行之前Pi 必须完成。此时称PiPj的直接前趋,而称PjPi的直接后继。

在前趋图中,把没有前趋的结点称为初始结点(Initial Node),把没有后继的结点称为终止结点。此外,每个结点还具有一个重量,用于表示该结点所含有的程序量或程序的执行时间。

前趋图中是不允许有循环的,否则必然会产生不可能实现的前趋关系。

1.2 程序的顺序执行

一个应用程序由若干个程序段组成,每一个程序段完成特定的功能,它们在执行时,都需要按照某种先后次序顺序执行,仅当前一程序段执行完后,才运行后一程序段。

程序顺序执行的特征:

  • 顺序性:指处理机严格地按照程序所规定的顺序执行,即每一操作必须在下一个操作开始之前结束。

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

  • 可再现性:指只要程序执行时的环境和初始条件相同,当程序重复执行时,不论它是从头到尾不停顿地执行,还是“停停走走”地执行,都可获得相同的结果

1.3 程序的并发执行

只有在不存在前趋关系的程序之间才有可能并发执行,否则无法并发执行。

程序并发执行的特征:

引入了程序间的并发执行功能后,虽然提高了系统的吞吐量和资源利用率,但由于它们共享系统资源,以及它们为完成同一项任务而相互合作,致使在这些并发执行的程序之间必将形成相互制约的关系。

  • 间断性。

  • 失去封闭性。

  • 不可再现性。

2. 进程的描述

2.1 进程的定义和特征

在多道程序环境下,程序的执行属于并发执行,此时它们将失去其封闭性,并具有间断性,以及其运行结果不可再现性的特征。由此,决定了通常的程序是不能参与并发执行的,否则,程序的运行也就失去了意义。为了能使程序并发执行,并且可以对并发执行的程序加以描述和控制,人们引入了进程的概念。

进程的定义:

  • 进程是程序的一次执行。

  • 进程是一个程序及其数据在处理机上顺序执行时所发生的活动。

  • 进程是具有独立功能的程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位。

  • 进程可以和别的进程并行执行计算。

进程的特征:

  • **动态性。

    进程实质是进程实体的执行过程,其动态性还表现在它由创建而产生,由调度而执行,由撤销而消亡。进程实体有一定的生命周期。

  • 并发性。

    指多个进程实体同存在于内存中,且能在一段时间内同时运行。

  • 独立性。

    指进程实体是一个能独立运行、独立获得资源和独立接受调度的基本单位

  • 异步性。

    指进程是按异步方式运行的,即按各自独立的、不可预知的速度向前推进

  • 结构特性。

    进程 = 程序段 + 数据段 + 进程控制块PCB

2.2 进程的基本状态及转换

由于多个进程在并发执行时共享系统资源,致使它们在运行过程中呈现间断性的运行规律,所以进程在其生命周期内可能具有多种状态。

进程的三种基本状态:

  • 就绪状态。

    指进程已处于准备好运行的状态,即进程已分配到除CPU以外的所有的必要资源后,只要再获得CPU便可立即执行。

  • 执行状态。

    指进程以获得CPU,其程序正在执行的状态。

    对任何一个时刻而言:

    • 在单处理机系统中,只有一个进程处于执行状态;

    • 在多处理机系统中,则有多个进程处于执行状态。

  • 阻塞状态。

    指正在执行的进程由于发生某事件(如O请求、申请缓冲区失败等)暂时无法继续执行时的状态,亦即进程的执行受到阻塞。

进程调度:

OS把处理机分配给另一个就绪进程,而让受阻进程处于暂停状态,一般将这种暂停状态称为阻塞状态,有时也称为等待状态或封锁状态。

阻塞队列:

通常系统将处于阻塞状态的进程也排成一个队列,称该队列为阻塞队列。

实际上,在较大的系统中,为了减少队列操作的开销,提高系统效率,根据阻塞原因的不同,会设置多个阻塞队列。

创建状态和终止状态:

  • 创建状态。

    进程是由创建而产生。

    进程的创建方式:

    1. 首先由进程申请一个空白PCB,并向PCB中填写用于控制和管理进程的信息;

    2. 然后为该进程分配运行时所必须的资源;

    3. 最后,把该进程转入就绪状态并插入就绪队列之中。

  • 终止状态。

    也称为结束态

    进程的终止方式:

    1. 首先,是等待操作系统进行善后处理;

    2. 最后将其PCB清零,并将PCB空间返还系统。

进入终止态的进程以后不能再执行,但在操作系统中依然保留一个记录,其中保存状态码和一些计时统计数据,供其他进程收集。

一旦其他进程完成了对其信息的提取之后,操作系统将删除该进程,即将其PCB清零,并将该空白PCB返还系统。

2.3 挂起操作和进程状态的转换

挂起操作:当该操作作用于某个进程时该进程将被挂起,意味着此时该进程处于静止状态。如果进程正在执行,它将暂停执行。若原本处于就绪状态,则该进程此时暂不接受调度。与挂起操作对应的操作是激活操作。

引入挂起操作的原因:

  • 终端用户的需要。

  • 父进程请求。

  • 负荷调节的需要。

  • 操作系统的需要。

引入挂起原语操作后三个进程状态的转换:

  • 活动就绪→静止就绪。

    当进程处于未被挂起的就绪状态时,称此为活动就绪状态,此时进程可以接受调度。

    当用挂起原语将该进程挂起后,该进程便转变为静止就绪状态,处于静止就绪状态的进程不再被调度执行。

  • 活动阻塞→静止阻塞。

    当进程处于未被挂起的阻塞状态时,称它是处于活动阻塞状态

    挂起原语将它挂起后,进程便转变为静止阻塞状态。处于该状态的进程在其所期待的事件出现后,它将从静止阻塞变为静止就 绪状态。

  • 静止就绪→活动就绪。处于静止就绪状态的进程若用激活原语激活后,该进程将转变为活动就绪状态

  • 静止阻塞→活动阻塞。处于静止阻塞状态的进程若用激活原语激活后,进程将转变为活动阻塞状态

引入挂起操作后五个进程状态的转换:

  • NULL→创建:一个新进程产生时,该进程处于创建状态。

  • 创建→活动就绪:在当前系统的性能和内存的容量均允许的情况下,完成对进程创建的必要操作后,相应的系统进程将进程的状态转换为活动就绪状态。

  • 创建→静止就绪:考虑到系统当前资源状况和性能的要求,不分配给新建进程所需资源,主要是主存,相应的系统将进程状态转为静止就绪状态,被安置在外存,不参与调度,此时进程创建工作尚未完成。

  • 执行→终止:当一个进程已完成任务时,或是出现了无法克服的错误,或是被OS或是被其他进程所终结,此时将进程的状态转换为终止状态。

2.4 进程管理中的数据结构

在计算机系统中,对于每个资源和每个进程都设置了一个数据结构,用于表征其实体,我们称之为资源信息表或进程信息表,其中包含了资源或进程的标识、描述、状态等信息以及一批指针。通过这些指针,可以将同类资源或进程的信息表,或者同一进程所占用的资源信息表分类链接成不同的队列,便于操作系统进行查找。

操作系统中用于管理控制的数据结构:

OS管理的这些数据结构一般分内存表、设备表、文件表和用于进程管理的进程表,通常进程表又被称为进程控制块PCB。

进程控制块PCB的作用:

  • 作为独立运行基本单位的标志。

  • 能实现间断性运行方式。

  • 提供进程管理所需要的信息。

  • 提供进程调度所需要的信息。

  • 实现与其它进程的同步与通信。

进程控制块中的信息:

  1. 进程标识符。

    进程标识符用于唯一地标识一个进程。

    一个进程通常有两种标识符:

    • 外部标识符。

    • 内部标识符。

  2. 处理机状态。

    处理机状态信息也称为处理机的上下文,主要是由处理机的各种寄存器中的内容组成的。

  3. 进程调度信息。

在OS进行调度时,必须了解进程的状态及有关进程调度的信息,这些信息包括:

  1. 进程状态,指明进程的当前状态,它是作为进程调度和对换时的依据;

  2. 进程优先级,是用于描述进程使用处理机的优先级别的一个整数,优先级高的进程应优先获得处理机;

  3. 进程调度所需的其它信息,它们与所采用的进程调度算法有关,比如,进程已等待CPU的时间总和、进程已执行的时间总和等。

  4. 事件,是指进程由执行状态转变为阻塞状态所等待发生的事件,即阻塞原因。

  1. 进程控制信息

用于进程控制所必须的信息,它包括:

  1. 程序和数据的地址,进程实体中的程序和数据的内存或外存地(首)址,以便再调度到该进程执行时,能从PCB中找到其程序和数据;

  2. 进程同步和通信机制,这是实现进程同步和进程通信时必需的机制,如消息队列指针、信号量等,它们可能全部或部分地放在PCB中;

  3. 资源清单,在该清单中列出了进程在运行期间所需的全部资源(除CPU以外),另外还有一张已分配到该进程的资源的清单;

  4. 链接指针,它给出了本进程(PCB)所在队列中的下一个进程的PCB的首地址。

进程控制块的组织方式:

  • 线性方式。

    将系统中所有的PCB都组织在一张线性表中,将该表的首址存放在内存的一个专用区域中。

    该方式实现简单、开销小,但每次查找时都需要扫描整张表,因此适合进程数目不多的系统。

  • 链接方式。

    把具有相同状态进程的PCB分别通过PCB中的链接字链接成一个队列。这样,可以形成就绪队列、若干个阻塞队列和空白队列等。

    对就绪队列而言,往往按进程的优先级将PCB从高到低进行排列,将优先级高的进程PCB排在队列的前面。

    同样,也可把处于阻塞状态进程的PCB根据其阻塞原因的不同,排成多个阻塞队列,如等待I/O操作完成的队列和等待分配内存的队列等。

  • 索引方式。

    系统根据所有进程状态的不同,建立几张索引表。例如,就绪索引表、阻塞索引表等,并把各索引表在内存的首地址记录在内存的一些专用单元中。

    在每个索引表的表目中,记录具有相应状态的某个PCB在PCB表中的地址。

3. 进程控制

进程控制一般是由OS的内核中的原语来实现的。其目的是实现多进程高效率的并发执行和协调,以及实现资源共享。

3.1 操作系统内核

通常将一些与硬件紧密相关的模块(如中断处理程序等)、各种常用设备的驱动程序以及运行频率较高的模块(如时钟管理、进程调度和许多模块所公用的一些基本操作),都安排在紧靠硬件的软件层次中,将它们常驻内存,即被称为OS内核

这种安排方式的目的在于两方面:

  1. 便于对这些软件进行保护,防止遭受其他应用程序的破坏;

  2. 可以提高 OS 的运行效率。

OS内核的两大方面功能:

  • 支撑功能。

    1. 中断处理。

      中断处理是内核最基本的功能,是整个操作系统赖以活动的基础,OS中许多重要的活动,如各种类型的系统调用、键盘命令的输入、进程调度、设备驱动等,无不依赖于中断。

      通常,为减少处理机中断的时间,提高程序执行的并发性,内核在对中断进行“有限处理”后,便转入相关的进程,由这些进程继续完成后续的处理工作。

    2. 时钟管理。

      时钟管理是内核的一项基本功能,在OS中的许多活动都需要得到它的支撑,如在时间片轮转调度中,每当时间片用完时,便由时钟管理产生一个中断信号,促使调度程序重新进行调度。

      在实时系统中的截止时间控制、批处理系统中的最长运行时间控制等,也无不依赖于时钟管理功能。

    3. 原语操作。

      原语(Primitive),就是由若干条指令组成的,用于完成一定功能的一个过程。

      它与一般过程的区别在于:它们是“原子操作(Action Operation)”。所谓原子操个操作中的所有动作要么全做,要么全不做。换言之,它是一个不可分割的基本单位。

      原语在执行过程中不允许被中断。原子操作在系统态下执行,常驻内存。在内核中可能有许多原语,如用于对链表进行操作的原语、用于实现进程同步的原语等。

  • 资源管理功能。

    1. 进程管理。

    2. 存储器管理。

    3. 设备管理。

3.2 进程的创建

进程的层次结构:

在OS中,允许一个进程创建另一个进程,通常把创建进程的进程称为父进程,而把被创建的进程称为子进程。子进程可继续创建更多的孙进程,由此便形成了一个进程的层次结构。

  • 子进程可以继承父进程所拥有的资源;

  • 当子进程被撤销时,应将其从父进程那里获得的资源归还给父进程;

  • 在撤销父进程时,也必须同时撤销其所有的子进程;

  • 进程不能拒绝其子进程的继承权。

进程图:

进程图就是用于描述进程间关系的一棵有向树,节点代表进程。

引起创建进程的事件:

  • 用户登录。

  • 作业调度。

  • 提供服务。

  • 应用请求。

进程的创建过程。

  1. 申请空白PCB,为新进程申请获得唯一的数字标识符(PID),并从PCB集合中索取一个空白PCB。

  2. 为新进程分配其运行所需的资源,包括各种物理和逻辑资源,如内存、文件、I/O设备和CPU时间等。

  3. 初始化进程控制块(PCB)。

创建态结束。

  1. 如果进程就绪队列能够接纳新进程,便将新进程插入就绪队列。

就绪态完成。

3.3 进程的终止

引起进程终止的事件:

  • 正常结束;

  • 异常结束;

  • 外界干预。

进程的终止过程。

  1. 根据被终止进程的标识符,从PCB集合中检索出该进程的PCB,从中读出该进程的状态;

  2. 若被终止进程正处于执行状态,应立即终止该进程的执行,并置调度标志为真,用于指示该进程被终止后应重新进行调度;

  3. 若该进程还有子孙进程,还应将其所有子孙进程也都予以终止,以防它们成为不可控的进程;

  4. 将被终止进程所拥有的全部资源或者归还给其父进程,或者归还给系统;

执行态结束,就绪态开始。

  1. 将被终止进程(PCB)从所在队列(或链表)中移出,等待其它程序来搜集信息。

3.4 进程的阻塞与唤醒

唤醒原语是V原语(主动);

阻塞原语是P原语(被动)。

引起进程阻塞和唤醒的事件:

  • 向系统请求共享资源失败。

  • 等待某种操作的完成。

  • 新数据尚未到达。

  • 等待新任务的到达。

进程阻塞的过程。

  • 正在执行的进程,如果发生了上述某事件,进程便通过调用阻塞原语block将自己阻塞。

  • 阻塞是进程自身的一种主动行为。

  1. 进入block过程后,由于该进程还处于执行状态,所以应先立即停止执行,把进程控制块中的现行状态由“执行”改为阻塞,并将PCB插入阻塞队列。

  2. 如果系统中设置了因不同事件而阻塞的多个阻塞队列,则应将本进程插入到具有相同事件的阻塞队列。

  3. 随后,转调度程序进行重新调度,将处理机分配给另一就绪进程,并进行切换;

  4. 最终,保留被阻塞进程的处理机状态,按新进程的PCB中的处理机状态设置CPU的环境。

进程唤醒的过程。

  • 当被阻塞进程所期待的事件发生时,比如它所启动的I/O操作已完成,或其所期待的数据已经到达,则由有关进程(比如提供数据的进程)调用唤醒原语wakeup,将等待该事件的进程唤醒。

  • wakeup执行的过程是:

    1. 首先把被阻塞的进程从等待该事件的阻塞队列中移出,将其PCB中的现行状态由阻塞改为就绪,

    2. 然后再将该PCB插入到就绪队列中。

3.5 进程的挂起与激活

进程的挂起过程。

当系统中出现了引起进程挂起的事件时,OS将利用挂起原语suspend将指定进程或处于阻塞状态的进程挂起。

  • suspend的执行过程:

    1. 首先检查被挂起进程的状态,若处于活动就绪状态,便将其改为静止就绪;对于活动阻塞状态的进程,则将之改为静止阻塞。

    2. 为了方便用户或父进程考查该进程的运行情况,而把该进程的PCB复制到某指定的内存区域。

    3. 最后,若被挂起的进程正在执行,则转向调度程序重新调度。

进程的激活过程。

当系统中发生激活进程的事件时,OS将利用激活原语active,将指定进程激活。

  • 激活原语先将进程从外存调入内存,检查该进程的现行状态,若是静止就绪,便将之改为活动就绪;若为静止阻塞,便将之改为活动阻塞。

  • 假如采用的是抢占调度策略,则每当有静止就绪进程被激活而插入就绪队列时,便应检查是否要进行重新调度,即由调度程序将被激活的进程与当前进程两者的优先级进行比较,如果被激活进程的优先级低,就不必重新调度;否则,立即剥夺当前进程的运行,把处理机分配给刚刚被激活的进程。

4. 进程同步

在OS中引入进程后,一方面可以使系统中的多道程序并发执行,这不仅能有效地改善资源利用率,还可显著地提高系统的吞吐量,但另一方面却使系统变得更加复杂。

如果不能采取有效的措施,对多个进程的运行进行妥善的管理,必然会因为这些进程对系统资源的无序争夺给系统造成混乱。致使每次处理的结果存在着不确定性,即显现出其不可再现性。

4.1 进程同步的基本概念

两种形式的制约关系:

  • 间接相互制约关系。

    多个程序在并发执行时,由于共享系统资源(如CPU、I/O设备等),致使在这些并发执行的程序之间形成相互制约的关系。

  • 直接相互制约关系。

    某些应用程序,为了完成某任务而建立了两个或多个进程。这些进程将为完成同一项任务而相互合作。进程间的直接制约关系就是源于它们之间的相互合作。

临界资源:

许多硬件资源如打印机、 磁带机等,都属于临界资源,诸进程间应采取互斥方式,实现对这种资源的共享。

临界区:

不论是硬件临界资源还是软件临界资源,多个进程必须互斥地对它进行访问。人们把在每个进程中访问临界资源的那段代码称为临界区

若能保证诸进程互斥地进入自己的临界区,便可实现诸进程对临界资源的互斥访问。

同步机制应遵循的规则:

  1. 空闲让进。

  2. 忙则等待。

  3. 有限等待。

  4. 让权等待。

4.2 硬件同步机制

目前许多计算机已提供了一些特殊的硬件指令,允许对一个字中的内容进行检测和修正,或者是对两个字的内容进行交换等。可利用这些特殊的指令来解决临界区问题。

关中断。

  • 关中断是实现互斥的最简单的方法之一。

  • 在进入锁测试之前关闭中断,直到完成锁测试并上锁之后才能打开中断。这样,进程在临界区执行期间,计算机系统不响应中断,从而不会引发调度,也就不会发生进程或线程切换。由此,保证了对锁的测试和关锁操作的连续性和完整性,有效地保证了互斥。

  • 关中断的方法存在许多缺点

    1. 滥用关中断权力可能导致严重后果;

    2. 关中断时间过长,会影响系统效率,限制了处理器交叉执行程序的能力;

    3. 关中断方法也不适用于多CPU 系统,因为在一个处理器上关中断并不能防止进程在其它处理器上执行相同的临界段代码。

利用Test-and-Set指令实现互斥。

  • 这是一种借助一条硬件指令“测试并建立”指令TS(Test-and-Set)以实现互斥的方法。

在许多计算机中都提供了这种指令。

利用Swap指令实现进程互斥。

  • 该指令称为对换指令,在Intel 80x86中又称为XCHG指令,用于交换两个字的内容。

4.3 信号量机制

整型信号量:

  • 最初由Dijkstra把整型信号量定义为一个用于表示资源数目的整型量S,它与一般整型量不同,除初始化外,仅能通过两个标准的原子操作(Atomic Operation) wait(S)signal(S)来访问。

  • 很长时间以来,这两个操作一直被分别称为P、V操作

记录型信号量:

  • 在整型信号量机制中的wait操作,只要是信号量S≤0,就会不断地测试。因此,该机制并未遵循“让权等待”的准则,而是使进程处于“忙等”的状态。

  • 记录型信号量机制则是一种不存在“忙等”现象的进程同步机制。但在采取了“让权等待”的策略后,又会出现多个进程等待访问同一临界资源的情况。为此,在信号量机制中,除了需要一个用于代表资源数目的整型变量value外,还应增加一个进程链表指针list,用于链接上述的所有等待进程。

AND型信号量:

  • 在有些应用场合,是一个进程往往需要获得两个或更多的共享资源后方能执行其任务。假定现有两个进程A和B,它们都要求访问共享数据D和E,当然,共享数据都应作为临界资源。

  • AND同步机制的基本思想是:将进程在整个运行过程中需要的所有资源,一次性全部地分配给进程,待进程使用完后再一起释放。只要尚有一个资源未能分配给进程,其它所有可能为之分配的资源也不分配给它。亦即,对若干个临界资源的分配采取原子操作方式要么把它所请求的资源全部分配到进程,要么一个也不分配。

信号量集:

在前面所述的记录型信号量机制中,wait(S)signal(S)操作仅能对信号量施以加1或减1操作,意味着每次只能对某类临界资源进行一个单位的申请或释放。

  • 当一次需要N个单位时,便要进行N次wait(S)操作,这显然是低效的,甚至会增加死锁的概率。

  • 此外,在有些情况下,为确保系统的安全性,当所申请的资源数量低于某一下限值时,还必须进行管制,不予以分配。

  • 因此,当进程申请某类临界资源时,在每次分配之前,都必须测试资源的数量,判断是否大于可分配的下限值,决定是否予以分配。

4.4 信号量的应用

  • 利用信号量实现进程互斥。

  • 利用信号量实现前趋关系。

4.5 管程机制

管程的定义:

  • 系统中的各种硬件资源和软件资源均可用数据结构抽象地描述其资源特性,即用少量信息和对该资源所执行的操作来表征该资源,而忽略它们的内部结构和实现细节。

  • 可以利用共享数据结构抽象地表示系统中的共享资源,并且将对该共享数据结构实施的特定操作定义为一组过程。进程对共享资源的申请、释放和其它操作必须通过这组过程,接地对共享数据结构实现操作。

  • 代表共享资源的数据结构以及由对该共享数据结构实施操作的一组过程所组成的资源管理程序共同构成了一个操作系统的资源管理模块,我们称之为管程。

  • Hansan为管程所下的定义是:一个管程定义了一个数据结构和能为并发进程所执行(在该数据结构上)的一组操作,这组操作能同步进程和改变管程中的数据

  • 管程由四部分组成:

    1. 管程的名称;

    2. 局部于管程的共享数据结构说明;

    3. 对该数据结构进行操作的一组过程;

    4. 对局部于管程的共享数据设置初始值的语句。

  • 管程中包含了面向对象的思想,它将表征共享资源的数据结构及其对数据结构操作的一组过程,包括同步机制,都集中并封装在一个对象内部,隐藏了实现细节。

  • 封装于管程内部的数据结构仅能被封装于管程内部的过程所访问,任何管程外的过程都不能访问它;反之,封装于管程内部的过程也仅能访问管程内的数据结构。

  • 所有进程要访问界资源时,都只能通过管程间接访问,而管程每次只准许一个进程进入管程,执行管程的过程,从而实现了进程互斥。

  • 管程的特性:

    1. 模块化;

    2. 抽象数据类型;

    3. 信息掩蔽。

管程和进程的区别:

  1. 虽然二者都定义了数据结构,但进程定义的是私有数据结构PCB管程定义的是公共数据结构,如消息队列等。

  2. 二者都存在对各自数据结构上的操作,但进程是由顺序程序执行有关操作,而管程主要是进行同步操作和初始化操作

  3. 设置进程的目的在于实现系统的并发性,而管程的设置则是解决共享资源的互斥使用问题

  4. 进程通过调用管程中的过程对共享数据结构实行操作,该过程就如通常的子程序一样被调用,因而管程为被动工作方式进程则为主动工作方式

  5. 进程之间能并发执行,而管程则不能与其调用者并发

  6. 进程具有动态性,由“创建”而诞生,由“撤消”而消亡,而管程则是操作系统中的一个资源管理模块,供进程调用。

条件变量:

  • 在利用管程实现进程同步时,必须设置同步工具,如两个同步操作原语waitsignal

  • 当某进程通过管程请求获得临界资源而未能满足时,管程便调用wait原语使该进程等待,并将其排在等待队列上。

  • 仅当另一进程访问完成并释放该资源之后,管程才又调用signal原语,唤醒等待队列中的队首进程。

5. 经典进程的同步问题

5.1 生产者-消费者问题

利用记录型信号量解决生产者-消费者问题:

  • 假定在生产者和消费者之间的公用缓冲池中具有n个缓冲区,这时可利用互斥信号量mutex实现诸进程对缓冲池的互斥使用;

  • 利用信号量emptyfull分别表示缓冲池中空缓冲区和满缓冲区的数量。

  • 又假定这些生产者和消费者相互等效,只要缓冲池未满,生产者便可将消息送入缓冲池;只要缓冲池未空,消费者便可从缓冲池中取走一个消息。

利用AND信号量解决生产者-消费者问题:

  • 对于生产者-消费者问题,也可利用AND信号量来解决。

    1. Swait(empty,mutex)来代替wait(empty)和wait(mutex)

    2. Ssignal(mutex,full)来代替signal(mutex)signal(full)

    3. Swait(full,mutex)代替wait(full)和wait(mutex);

    4. Ssignal(mutex,empty)代替Signal(mutex)Signal(empty)

利用管程解决生产者-消费者问题:

  • 在利用管程方法来解决生产者-消费者问题时,首先便是为它们建立一个管程,并命名为procducerconsumer,或简称为PC。其中包括两个过程:

    1. put(x)过程。

    2. get(x)过程。

  • 对于条件变量notfullnotempty,分别有两个过程cwaitcsignal对它们进行操作:

    1. cwait(condition)过程:当管程被一个进程占用时,其他进程调用该过程时阻塞,并挂在条件condition的队列上。

    2. csignal(condition)过程:唤醒在cwait执行后阻塞在条件condition队列上的进程,如果这样的进程不止一个,则选择其中一个实施唤醒操作;如果队列为空,则无操作而返回。

5.2 哲学家进餐问题

利用记录型信号量解决哲学家进餐问题:

经分析可知,放在桌子上的筷子是临界资源,在一段时间内只允许一位哲学家使用。为了实现对筷子的互斥使用,可以用一个信号量表示一只筷子,由这五个信号量构成信号量数组。

利用AND信号量机制解决哲学家进餐问题:

在哲学家进餐问题中,要求每个哲学家先获得两个临界资源(筷子)后方能进餐,这在本质上就是前面所介绍的AND同步问题,故用AND信号量机制可获得最简洁的解法。

5.3 读者-写者问题

利用记录型信号量解决读者-写者问题:

  • 为实现Reader与Writer进程间在读或写时的互斥而设置了一个互斥信号量Wmutex。另外,再设置一个整型变量Readcount表示正在读的进程数目。

  • 由于只要有一个Reader进程在读,便不允许Writer进程去写。因此,仅当Readcount=0,表示尚无Reader进程在读时,Reader进程才需要执行Wait(Wmutex)操作。若wait(Wmutex)操作成功,Reader进程便可去读,相应地,做Readcount+1操作。

利用信号量集机制解决读者-写者问题: 这里的读者—写者问题,与前面的略有不同,它增加了一个限制,即最多只允许RN个读者同时读。

为此,又引入了一个信号量L,并赋予其初值为RN,通过执行wait(L, 1, 1)操作来控制读者的数目,每当有一个读者进入时,就要先执行wait(L, 1, 1)操作,使L的值减1

当有RN个读者进入读后,L便减为0,第RN + 1个读者要进入读时,必然会因wait(L, 1, 1)操作失败而阻塞。

6. 进程间通信

信号量机制之所以低级的原因在于:

  1. 效率低,生产者每次只能向缓冲池投放一个产品(消息),消费者每次只能从缓冲区中取得一个消息;

  2. 通信对用户不透明,OS只为进程之间的通信提供了共享存储器。

在进程之间要传送大量数据时,应当利用OS提供的高级通信工具,该工具最主要的特点是:

  1. 使用方便。

    OS隐藏了实现进程通信的具体细节,向用户提供了一组用于实现高级通信的命令(原语),用户可方便地直接利用它实现进程之间的通信。或者说,通信过程对用户是透明的。这样就大大减少了通信程序编制上的复杂性。

  2. 高效地传送大量数据。

    用户可直接利用高级通信命令(原语)高效地传送大量的数据。

6.1 进程通信的类型

共享存储器系统(Shared-Memory System):

  • 在共享存储器系统中,相互通信的进程共享某些数据结构或共享存储区,进程之间能够通过这些空间进行通信。

  • 据此,又可把它们分成以下两种类型:

    1. 基于共享数据结构的通信方式。

      在这种通信方式中,要求诸进程公用某些数据结构,借以实现诸进程间的信息交换,如在生产者-消费者问题中的有界缓冲区。

      操作系统仅提供共享存储器,由程序员负责对公用数据结构的设置及对进程间同步的处理。

      这种通信方式仅适于传递相对少量的数据,通信效率低下,属于低级通信。

    2. 基于共享存储区的通信方式。

      为了传输大量数据,在内存中划出了一块共享存储区域,诸进程可通过对该共享区的读或写交换信息,实现通信,数据的形式和位置甚至访问控制都是由进程负责,而不是OS。

      这种通信方式属于高级通信。需要通信的进程在通信前,先向系统申请获得共享存储区中的一个分区,并将其附加到自己的地址空间中,便可对其中的数据进行正常读、写,读写完成或不再需要时,将其归还给共享存储区。

管道(pipe)通信系统:

  • 管道,是指用于连接一个读进程和一个写进程以实现它们之间通信的一个共享文件,又名pipe文件。

  • 向管道(共享文件)提供输入的发送进程(即写进程)以字符流形式将大量的数据送入管道;而接受管道输出的接收进程(即读进程)则从管道中接收(读)数据。

  • 由于发送进程和接收进程是利用管道进行通信的,故又称为管道通信。

这种方式首创于UNIX系统,由于它能有效地传送大量数据,因而又被引入到许多其它操作系统中。

  • 为了协调双方的通信,管道机制必须提供以下三方面的协调能力:

    1. 互斥,即当一个进程正在对pipe执行读/写操作时,其它(另一)进程必须等待。

    2. 同步,指当写(输入)进程把一定数量(如4 KB)的数据写入pipe,便去睡眠等待,直到读(输出)进程取走数据后再把它唤醒。当读进程读一空pipe时,也应睡眠等待,直至写进程将数据写入管道后才将之唤醒。

    3. 确定对方是否存在,只有确定了对方已存在时才能进行通信。

消息传递系统(Message passing system):

  • 在该机制中,进程不必借助任何共享存储区或数据结构,而是以格式化的消息 (message)为单位,将通信的数据封装在消息中,并利用操作系统提供的一组通信命令(原语),在进程间进行消息传递,完成进程间的数据交换。

  • 基于消息传递系统的通信方式属于高级通信方式,因其实现方式的不同,可进一步分成两类:

    1. 直接通信方式。

      指发送进程利用OS所提供的发送原语,直接把消息发送给目标进程。

    2. 间接通信方式。

      指发送和接收进程,都通过共享中间实体(称为邮箱)的方式进行消息的发送和接收,完成进程间的通信。

客户机-服务器系统(Client-Server system):

  • 套接字(Socket)。 套接字起源于20世纪70年代加州大学伯克利分校版本的UNIX(即BSD Unix),是UNIX 操作系统下的网络通信接口。

    一开始,套接字被设计用在同一台主机上多个应用程序之间的通信(即进程间的通信),主要是为了解决多对进程同时通信时端口和物理线路的多路复用问题。

    随着计算机网络技术的发展以及UNIX 操作系统的广泛使用,套接字已逐渐成为最流行的网络通信程序接口之一。

    一个套接字就是一个通信标识类型的数据结构,包含了通信目的的地址、通信使用的端口号、通信网络的传输层协议、进程所在的网络地址,以及针对客户或服务器程序提供的不同系统调用(或 API函数)等,是进程通信和网络通信的基本构件。

    套接字是为客户/服务器模型而设计的,通常,套接字包括两类:

    1. 基于文件型:

      通信进程都运行在同一台机器的环境中,套接字是基于本地文件系统支持的,一个套接字关联到一个特殊的文件,通信双方通过对这个特殊文件的读写实现通信,其原理类似于前面所讲的管道。

    1. 基于网络型:

      该类型通常采用的是非对称方式通信,即发送者需要提供接收者命名。

      通信双方的进程运行在不同主机的网络环境下,被分配了一对套接字,一个属于接收进程(或服务器端),一个属于发送进程(或客户端)。

      • 一般地,发送进程(或客户端)发出连接请求时,随机申请一个套接字,主机为之分配一个端口,与该套接字绑定,不再分配给其它进程。

      • 接收进程(或服务器端)拥有全局公认的套接字和指定的端口(如fp服务器监听端口为21,Web或http服务器监听端口为80),并通过监听端口等待客户请求。

      因此,任何进程都可以向它发出连接请求和信息请求,以方便进程之间通信连接的建立。接收进程(或服务器端)一旦收到请求,就接受来自发送进程(或客户端)的连接,完成连接,即在主机间传输的数据可以准确地发送到通信进程,实现进程间的通信;当通信结束时,系统通过关闭接收进程(或服务器端)的套接字撤销连接。

  • 远程过程调用和远程方法调用。 远程过程(函数)调用RPC(Remote Procedure Call),是一个通信协议,用于通过网络连接的系统。

    该协议允许运行于一台主机(本地)系统上的进程调用另一台主机(远程)系统上的进程,而对程序员表现为常规的过程调用,无需额外地为此编程。

    如果涉及的软件采用面向对象编程,那么远程过程调用亦可称做远程方法调用。

    负责处理远程过程调用的进程有两个:

    • 一个是本地客户进程;

    • 另一个是远程服务器进程。

    这两个进程通常也被称为网络守护进程,主要负责在网络间的消息传递,一般情况下这两个进程都是处于阻塞状态,等待消息。

    远程过程调用的主要步骤:

    1. 本地过程调用者以一般方式调用远程过程在本地关联的客户存根,传递相应的参数,然后将控制权转移给客户存根。

    2. 客户存根执行,完成包括过程名和调用参数等信息的消息建立,将控制权转移给本地客户进程。

    3. 本地客户进程完成与服务器的消息传递,将消息发送到远程服务器进程。

    4. 远程服务器进程接收消息后转入执行,并根据其中的远程过程名找到对应的服务器存根,将消息转给该存根。

    5. 该服务器存根接到消息后,由阻塞状态转入执行状态,拆开消息从中取出过程调用的参数,然后以一般方式调用服务器上关联的过程。

    6. 在服务器端的远程过程运行完毕后,将结果返回给与之关联的服务器存根。

    7. 该服务器存根获得控制权运行,将结果打包为消息,并将控制权转移给远程服务器进程。

    8. 远程服务器进程将消息发送回客户端。

    9. 本地客户进程接收到消息后,根据其中的过程名将消息存入关联的客户存根,再将控制权转移给客户存根。

    10. 客户存根从消息中取出结果,返回给本地调用者进程,并完成控制权的转移。

6.2 消息传递通信的实现方式

直接消息传递系统: 在直接消息传递系统中采用直接通信方式,即发送进程利用OS所提供的发送命令(原语),直接把消息发送给目标进程。

  1. 直接通信原语。

    • 对称寻址方式。

      该方式要求发送进程和接受进程都必须一显示方式提供对方的标识符。

      对称寻址方式的不足在于,一旦改变进程的名称,则可能需要检查所有其它进程的定义,有关对该进程旧名称的所有引用都必须查找到,以便将其修改为新名称,显然,这样的方式不利于实现进程定义的模块化。

    • 非对称寻址方式。

      某些情况下,接收进程可能需要与多个发送进程通信,无法事先指定发送进程。例如,用于提供打印服务的进程,它可以接收来自任何一个进程的“打印请求”消息。

      对于这样的应用,在接收进程的原语中,不需要命名发送进程,只填写表示源进程的参数,即完成通信后的返回值,而发送进程仍需要命名接收进程。

  1. 消息的格式。

    在消息传递系统中所传递的消息,必须具有一定的消息格式。

    在单机系统环境中,由于发送进程和接收进程处于同一台机器中,有着相同的环境,所以消息的格式比较简单,可采用比较短的定长消息格式,以减少对消息的处理和存储开销。

    该方式可用于办公自动化系统中,为用户提供快速的便笺式通信。但这种方式对于需要发送较长消息的用户是不方便的。

    为此,可采用变长的消息格式,即进程所发送消息的长度是可变的。对于变长消息,系统无论在处理方面还是存储方面,都可能会付出更多的开销,但其优点在于方便了用户。

  1. 进程的同步方式。

    在进程之间进行通信时,同样需要有进程同步机制,以使诸进程间能协调通信。

    不论是发送进程还是接收进程,在完成消息的发送或接收后,都存在两种可能性,即进程或者继续发送(或接收)或者阻塞

    由此,可得到三种情况:

    1. 发送进程阻塞,接收进程阻塞。这种情况主要用于进程之间紧密同步,发送进程和接收进程之间无缓冲时。

    2. 发送进程不阻塞、接收进程阻塞。这是一种应用最广的进程同步方式。平时,发送进程不阻塞,因而它可以尽快地把一个或多个消息发送给多个目标;而接收进程平时则处于阻塞状态直到发送进程发来消息时才被唤醒。

    3. 发送进程和接收进程均不阻塞。这也是一种较常见的进程同步形式。平时,发送进程和接收进程都在忙于自己的事情,仅当发生某事件使它无法继续运行时,才把自己阻塞起来等待。

  1. 通信链路。 为使在发送进程和接收进程之间能进行通信,必须在两者之间建立一条通信链路。有两种方式建立通信链路。

    • 第一种方式

      由发送进程在通信之前用显式的“建立连接”命令(原语)请求系统为之建立一条通信链路,在链路使用完后拆除链路。这种方式主要用于计算机网络中。

    • 第二种方式是:

      发送进程无须明确提出建立链路的请求,只须利用系统提供的发送命令(原语),系统会自动地为之建立一条链路。这种方式主要用于单机系统中。

    根据通信方式的不同,则又可把链路分成两种:

    1. 单向通信链路,只允许发送进程向接收进程发送消息,或者相反;

    2. 双向通信链路,即允许由进程A向进程B发送消息,也允许进程B同时向进程A发送消息。

信箱通信:

信箱通信属于间接通信方式,即进程之间的通信,需要通过某种中间实体(如共享数据结构等)来完成

该实体建立在随机存储器的公用缓冲区上,用来暂存发送进程发送给目标进程的消息;接收进程可以从该实体中取出发送进程发送给自己的消息,通常把这种中间实体称为邮箱(或信箱),每个邮箱都有一个唯一的标识符。

消息在邮箱中可以安全地保存,只允许核准的目标用户随时读取。

因此,利用邮箱通信方式既可实现实时通信,又可实现非实时通信。

  • 信箱的结构。 信箱定义为一种数据结构。在逻辑上,可以将其分为两个部分:

    1. 信箱头,用以存放有关信箱的描述信息,如信箱标识符、信箱的拥有者、信箱口 令、信箱的空格数等;

    2. 信箱体,由若干个可以存放消息(或消息头)的信箱格组成,信箱格的数目以及每格的大小是在创建信箱时确定的。

      在消息传递方式上,最简单的情况是单向传递。消息的传递也可以是双向的。

  • 信箱通信原语。

    1. 邮箱的创建和撤消。

      进程可利用邮箱创建原语来建立一个新邮箱,创建者进程应给出邮箱名字、邮箱属性(公用、私用或共享);对于共享邮箱,还应给出共享者的名字。

      当进程不再需要读邮箱时,可用邮箱撤消原语将之撤消。

    2. 消息的发送和接收。

      当进程之间要利用邮箱进行通信时,必须使用共享邮箱,并利用系统提供的下述通信原语进行通信。 Send(mailbox,message); 将一个消息发送到指定邮箱 Receive(mailbox,message); 从指定邮箱中接收一个消息

  • 信箱的类型。

    • 私用邮箱;

    • 公用邮箱;

    • 共享邮箱。

  • 在利用邮箱通信时,在发送进程和接收进程之间,存在以下四种关系:

    1. 一对一关系。

      发送进程和接收进程可以建立一条两者专用的通信链路,使两者之间的交互不受其他进程的干扰。

    1. 多对一关系。

      允许提供服务的进程与多个用户进程之间进行交互,也称为客户/服务器交互(clientserver interaction)。

    1. 一对多关系。

      允许一个发送进程与多个接收进程进行交互,使发送进程可用广播方式向接收者(多个)发送消息。

    1. 多对多关系。

      允许建立一个公用邮箱,让多个进程都能向邮箱中投递消息;也可从邮箱中取走属于自己的消息。

6.3 直接消息传递系统实例

消息缓冲队列通信机制中的数据结构:

  • 消息缓冲区。

    在消息缓冲队列通信方式中,主要利用的数据结构是消息缓冲区它可描述如下:

    typedef struct message_buffer{
        int sender;                     //发送者进程标识符
        int size;                       //消息长度
        char *text;                     //消息正文
        struct message_buffer *next;    //指向下一个消息缓冲区的指针
    }
  • PCB中有关通信的数据项。

    在操作系统中采用了消息缓冲队列通信机制时,除了需要为进程设置消息缓冲队列外,还应在进程的PCB中增加消息队列队首指针,用于对消息队列进行操作,以及用于实现同步的互斥信号量mutex和资源信号量sm

    在PCB中应加的数据项可描述如下:

    typedef struct processcontrol_block{
        //...
        struct message_buffer *mq;  //消息队列队首指针
        semaphore mutex;            //消息队列互斥信号量
        semaphore sm;               //消息队列资源信号量
        //...
    }PCB;
  • 发送原语。

  • 接收原语。

7. 线程的基本概念

在OS中引入进程的目的是为了使多个程序能并发执行,以提高资源利用率和系统吞吐量,那么,在操作系统中再引入线程,则是为了减少程序在并发执行时所付出的时空开销,使OS具有更好的并发性。

7.1 线程的引入

进程的两个基本属性:

  1. 进程是一个可拥有资源的独立单位。

    一个进程要能独立运行,它必须拥有一定的资源,包括用于存放程序正文、数据的磁盘和内存地址空间,以及它在运行时所需要的I/O设备、已打开的文件、信号量等。

  2. 进程同时又是一个可独立调度和分派的基本单位。

    一个进程要能独立运行,它还必须是一个可独立调度和分派的基本单位。

    每个进程在系统中有唯一的PCB,系统可根据其PCB感知进程的存在,也可以根据其PCB中的信息,对进程进行调度,还可将断点信息保存在其PCB中。反之,再利用进程PCB中的信息来恢复进程运行的现场。

正是由于进程有这两个基本属性,才使进程成为一个能独立运行的基本单位,从而也就构成了进程并发执行的基础。

程序并发执行所需付出的时空开销:

  1. 创建进程。

    系统在创建一个进程时,必须为它分配其所必需的、除处理机以外的所有资源,如内存空间、I/O设备,以及建立相应的PCB;

  2. 撤消进程。

    系统在撤消进程时,又必须先对其所占有的资源执行回收操作,然后再撤消PCB;

  3. 进程切换。

    对进程进行上下文切换时,需要保留当前进程的CPU环境,设置新选中进程的CPU环境,因而须花费不少的处理机时间。

线程作为调度和分派的基本单位。

7.2 进程和线程的比较

  • 调度的基本单位。

    1. 在传统的OS中,进程是作为独立调度和分派的基本单位,因而进程是能独立运行的基本单位。在每次被调度时,都需要进行上下文切换,开销较大。

    2. 在引入线程的OS中,已把线程作为调度和分派的基本单位,因而线程是能独立运行的基本单位。当线程切换时,仅需保存和设置少量寄存器内容,切换代价远低于进程。

    3. 在同一进程中,线程的切换不会引起进程的切换,但从一个进程中的线程切换到另一个进程中的线程时,必然就会引起进程的切换。

  • 并发性。

    1. 在引入线程的OS中,不仅进程之间可以并发执行,而且在一个进程中的多个线程之间亦可并发执行,甚至还允许在一个进程中的所有线程都能并发执行。

    2. 不同进程中的线程也能并发执行。这使得OS具有更好的并发性,从而能更加有效地提高系统资源的利用率和系统的吞吐量。

  • 拥有资源。

    1. 进程可以拥有资源,并作为系统中拥有资源的一个基本单位。

    2. 然而,线程本身并不拥有系统资源,而是仅有一点必不可少的、能保证独立运行的资源。

    比如,在每个线程中都应具有一个用于控制线程运行的线程控制块TCB、用于指示被执行指令序列的程序计数器保留局部变量、少数状态参数和返回地址等的一组寄存器和堆。

    1. 线程除了拥有自己的少量资源外,还允许多个线程共享该进程所拥有的资源。

      这首先表现在:

      • 属于同一进程的所有线程都具有相同的地址空间,这意味着,线程可以访问该地址空间中的每一个虚地址;

      • 此外,还可以访问进程所拥有的资源,如已打开的文件、定时器、信号量机构等的内存空间和它所申请到的I/O设备等

  • 独立性。

    1. 在同一进程中的不同线程之间的独立性要比不同进程之间的独立性低得多。

    2. 这是因为,为防止进程之间彼此干扰和破坏,每个进程都拥有一个独立的地址空间和其它资源,除了共享全局变量外,不允许其它进程的访问。

    3. 但是同一进程中的不同线程往往是为了提高并发性以及进行相互之间的合作面创建的,它们共享进程的内存地址空间和资源。

    • 如每个线程都可以访问它们所属进程地址空间中的所有地址;

    • 如一个线程的堆栈可以被其它线程读写,甚至完全清除。

    • 由一个线程打开的文件可以供其它线程读、写。

  • 系统开销。

    • 在创建或撤消进程时,系统都要为之分配和回收进程控制块、分配或回收其它资源,如内存空间和 JO 设备等。

    • OS为此所付出的开销,明显大于线程创建或撤消时所付出的开销。

    • 类似地,在进程切换时,涉及到进程上下文的切换,而线程的切换代价也远低于进程的。

    • 此外,由于一个进程中的多个线程具有相同的地址空间,线程之间的同步和通信也比进程的简单。

    • 因此,在一些OS中,线程的切换、同步和通信都无需操作系统内核的干预。

  • 支持多处理机系统。

    • 在多处理机系统中,对于传统的进程,即单线程进程,不管有多少处理机,该进程只能运行在一个处理机上。

    • 对于多线程进程,就可以将一个进程中的多个线程分配到多个处理机上,使它们并行执行,这无疑将加速进程的完成。

    因此,现代多处理机 OS都无一例外地引入了多线程。

7.3 线程的状态和和线程控制块

线程运行的三个状态:

  1. 执行状态,表示线程已获得处理机而正在运行。

  2. 就绪状态,指线程已具备了各种执行条件,只须再获得CPU便可立即执行。

  3. 阻塞状态,指线程在执行中因某事件受阻而处于暂停状态,例如,当一个线程执行从键盘读入数据的系统调用时,该线程就被阻塞。

线程控制块TCB的组成:

  1. 线程标识符,为每个线程赋予一个唯一的线程标识符。

  2. 一组寄存器,包括程序计数器PC状态寄存器和通用寄存器的内容。

  3. 线程运行状态,用于描述线程正处于何种运行状态。

  4. 优先级,描述线程执行的优先程度。

  5. 线程专有存储区,用于线程切换时存放现场保护信息,和与该线程相关的统计信息等。

  6. 信号屏蔽,即对某些信号加以屏蔽。

  7. 堆栈指针,在线程运行时,经常会进行过程调用,而过程的调用通常会出现多重嵌套的情况,这样,就必须将每次过程调用中所使用的局部变量以及返回地址保存起来。

多线程OS中的进程属性:

  • 进程是一个可拥有资源的基本单位。

    在多线程OS中,进程仍是作为系统资源分配的基本单位。

    任一进程所拥有的资源都包括:

    • 用户的地址空间、实现进程(线程)间同步和通信的机制、已打开的文件和已申请到的 I/O 设备,以及一张由核心进程维护的地址映射表,该表用于实现用户程序的逻辑地址到其存物理地址的映射。

  • 多个线程可并发执行。

    通常一个进程都含有若干个相对独立的线程,其数目可多可少,但至少要有一个线程。

    由进程为这些(个)线程提供资源及运行环境,使它们能并发执行。

    在 OS中的所有线程都只能属于某一个特定进程。实际上,现在把传统进程的执行方法称为单线程方法。

    如传统的UNIX系统能支持多用户进程,但只支持单线程方法

    反之,将每个进程支持多个线程执行的方法称为多线程方法。如Java的运行环境是单进程多线程的,Windows2000、Solaris、Mach等采用的则是多进程多线程的方法。

  • 进程已不是可执行的实体。

    在多线程OS中,是把线程作为独立运行(或称调度)的基本单位。

    此时的进程已不再是一个基本的可执行实体。虽然如此,进程仍具有与执行相关的状态。

    例如,所谓进程处于“执行”状态,实际上是指该进程中的某线程正在执行。

    此外,对进程所施加的与进程状态有关的操作也对其线程起作用。

    例如,在把某个进程挂起时,该进程中的所有线程也都将被挂起;又如,在把某进程激活时,属于该进程的所有线程也都将被激活。

8. 线程的实现

8.1 线程的实现方式

线程已在许多系统中实现,但各系统的实现方式并不完全相同。

在有的系统中,特别是一些数据库管理系统,如infomix所实现的是用户级线程; 而另一些系统(如MacintoshOS/2操作系统)所实现的是内核支持线程;还有一些系统如Solaris操作系统,则同时实现了这两种类型的线程。

内核支持线程KST(Kernel Supported Threads):

  • 在OS中的所有进程,无论是系统进程还是用户进程,都是在操作系统内核的支持下运行的,是与内核紧密相关的。而内核支持线程KST同样也是在内核的支持下运行的,它们的创建、阻塞、撤消和切换等,也都是在内核空间实现的。

  • 为了对内核线程进行控制和管理,在内核空间也为每一个内核线程设置了一个线程控制块,内核根据该控制块而感知某线程的存在,并对其加以控制。

  • 当前大多数OS都支持内核支持线程。

  • KST的优点:

    1. 在多处理器系统中,内核能够同时调度同一进程中的多个线程并行执行。

    2. 如果进程中的一个线程被阻塞了,内核可以调度该进程中的其它线程占有处理器运行,也可以运行其它进程中的线程。

    3. 内核支持线程具有很小的数据结构和堆栈,线程的切换比较快,切换开销小。

    4. 内核本身也可以采用多线程技术,可以提高系统的执行速度和效率。

用户级线程ULT(User Level Threads):

  • 用户级线程是在用户空间中实现的。

  • 对线程的创建、 撤消、同步与通信等功能,都无需内核的支持,即用户级线程是与内核无关的。

  • 在一个系统中的用户级线程的数目可以达到数百个至数千个。

  • 由于这些线程的任务控制块都是设置在用户空间,而线程所执行的操作也无需内核的帮助,因而内核完全不知道用户级线程的存在。

  • ULT的优点:

    1. 线程切换不需要转换到内核空间。

    2. 调度算法可以是进程专用的。

    3. 用户级线程的实现与OS平台无关,因为对于线程管理的代码是属于用户程序的一部分,所有的应用程序都可以对之进行共享。

  • ULT的缺点:

    1. 系统调用的阻塞问题。

      在基于进程机制的OS中,大多数系统调用将使进程阻塞,因此,当线程执行一个系统调用时,不仅该线程被阻塞,而且,进程内的所有线程会被阻塞。而在内核支持线程方式中,则进程中的其它线程仍然可以运行。

    2. 在单纯的用户级线程实现方式中,多线程应用不能利用多处理机进行多重处理的优点,内核每次分配给一个进程的仅有一个CPU,因此,进程中仅有一个线程能执行,在该线程放弃CPU之前,其它线程只能等待

组合方式:

有些OS把用户级线程和内核支持线程两种方式进行组合,提供了组合方式ULT/KST 线程。

在组合方式线程系统中,内核支持多个内核支持线程的建立、调度和管理,同时,也允许用户应用程序建立、调度和管理用户级线程。

  • 多对一模型,即将用户线程映射到一个内核控制线程。

  • 一对一模型,即将每一个用户级线程映射到一个内核支持线程。

  • 多对多模型,即将许多用户线程映射到同样数量或更少数量的内核线程上。

8.2 线程的实现

内核支持线程的实现:

  • 在仅设置了内核支持线程的OS中,一种可能的线程控制方法是,系统在创建一个新进程时,便为它分配一个任务数据区PTDA(Per Task Data Area),其中包括若干个线程控制块TCB空间。

用户级线程的实现:

  • 运行时系统(Runtime System)

    运行时系统,实质上是用于管理和控制线程的函数(过程)的集合,其中包括用于创建和撤消线程的函数、线程同步和通信的函数,以及实现线程调度的函数等。

    正因为有这些函数,才能使用户级线程与内核无关。

    运行时系统中的所有函数都驻留在用户空间,并作为用户级线程与内核之间的接口。

  • 内核控制线程 这种线程又称为轻型进程LWP(Light Weight Process)。

    每一个进程都可拥有多个LWP,同用户级线程一样,每个LWP都有自己的数据结构(如TCB),其中包括线程标识符、优先级、状态,另外还有栈和局部存储区等。

    LWP也可以共享进程所拥有的资源。LWP可通过系统调用来获得内核提供的服务,这样,当一个用户级线程运行时,只须将它连接到一个LWP上,此时它便具有了内核支持线程的所有属性。这种线程实现方式就是组合方式。

8.3 线程的创建和终止

线程的创建:

  • 应用程序在启动时,通常仅有一个线程在执行,人们把线程称为“初始化线程”,它的主要功能是用于创建新线程。

  • 在创建新线程时,需要利用一个线程创建函数(或系统调用),并提供相应的参数,如指向线程主程序的入口指针、堆栈的大小,以及用于调度的优先级等。

  • 在线程的创建函数执行完后,将返回一个线程标识符供以后使用。

线程的终止:

  • 当一个线程完成了自己的任务(工作)后,或是线程在运行中出现异常情况而须被强行终止时,由终止线程通过调用相应的函数(或系统调用)对它执行终止操作。

  • 但有些线程(主要是系统线程),它们一旦被建立起来之后,便一直运行下去而不被终止。

  • 在大多数的OS中,线程被中止后并不立即释放它所占有的资源,只有当进程中的其它线程执行了分离函数后,被终止的线程才与资源分离,此时的资源才能被其它线程利用。

9. 补充

  • 什么是前趋图?为什么要引入前趋图?

    前趋图(Precedence Graph)是一个有向无循环图(Directed Acyclic Graph,DAG),用于描述程序(或进程)之间先后执行顺序的关系。它由结点和有向边两部分组成,每个结点代表一个程序段、进程、语句等,结点间的有向边表示结点之间的前驱关系。从结点Si到结点Sj的有向边表示它们的前趋关系,记为Si→Sj,即Si和Sj应顺序执行,Sj仅在Si执行完成后才能开始执行。

    引入前趋图的原因主要有以下几点:

    1. 描述程序执行顺序:在程序设计中,为了清晰地表示各个程序段或进程之间的执行顺序,需要一种直观的图示方法。前趋图通过结点和有向边的方式,能够准确地描述出程序段或进程之间的先后执行关系。

    2. 优化程序执行:通过前趋图,可以分析出程序中的并行执行部分和串行执行部分,从而优化程序的执行效率。例如,在并发执行的环境中,可以充分利用系统资源,使得多个程序段或进程能够同时执行,提高系统的吞吐量。

    3. 解决资源竞争问题:在并发执行的环境中,多个程序段或进程可能会竞争共享资源。通过前趋图,可以分析出资源的使用情况,从而避免资源竞争导致的死锁等问题。

    4. 提高程序的可维护性:前趋图不仅可以帮助程序员理解程序的执行流程,还可以作为程序文档的一部分,方便后续的维护和修改。当程序需要更新或修改时,可以通过修改前趋图来反映程序的变化,从而确保程序的正确性和稳定性。

    综上所述,前趋图在程序设计和执行过程中起着重要的作用,它不仅能够清晰地描述程序段或进程之间的执行顺序,还能够优化程序的执行效率、解决资源竞争问题以及提高程序的可维护性。

  • 为什么程序并发执行会产生间断性特征?

    程序并发执行会产生间断性特征,这主要是由于以下几个方面的原因:

    1. 资源共享与竞争:在并发执行的环境中,多个程序需要共享系统中的各种资源,如CPU、内存、I/O设备等。由于资源的有限性,这些程序在执行过程中会相互竞争资源。当一个程序需要访问某个资源而该资源正被其他程序占用时,它必须等待资源释放后才能继续执行。这种等待和竞争的过程导致了程序执行的间断性。

    2. 程序间的相互制约:并发执行的程序之间为了完成同一项任务或达到某个共同目标,需要相互合作和协调。这种合作和协调的过程中,程序之间会形成相互制约的关系。例如,一个程序可能需要等待另一个程序提供的数据或结果才能继续执行。这种相互制约的关系也会导致程序执行的间断性。

    3. 系统调度与切换:操作系统为了充分利用系统资源,提高系统的吞吐量,会采用一定的调度算法来管理并发执行的程序。这些调度算法会根据程序的优先级、资源需求等因素来决定程序的执行顺序和时间。因此,在并发执行的环境中,程序的执行会受到系统调度的影响,出现间断性的特征。

    综上所述,程序并发执行产生间断性特征的原因主要包括资源共享与竞争、程序间的相互制约以及系统调度与切换等方面。这种间断性特征是并发执行环境中的一种固有现象,需要通过合理的调度和资源管理策略来加以应对和优化。

  • 程序并发执行时为什么会失去封闭性和可再现性?

    程序并发执行时会失去封闭性和可再现性,这主要是由于并发执行环境中的一些固有特性所导致的。以下是对这两个概念及其失去原因的具体解释:

    封闭性:

    1. 定义

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

    2. 失去原因

      • 在程序并发执行时,多个程序共享系统中的各种资源。这些资源的状态由多个程序共同改变,导致程序的运行不再仅受初始条件的影响,而是受到其他并发程序的影响。因此,程序的封闭性被破坏。

    可再现性:

    1. 定义

      • 可再现性是指在相同的初始条件和环境下,程序多次执行时能够得到相同的结果。

    2. 失去原因

      • 由于并发执行环境中存在资源共享和程序执行的随机性,即使程序的初始条件和执行环境相同,多次执行时也可能因为其他并发程序的影响而导致结果不同。因此,程序的可再现性被破坏。

      • 具体来说,并发程序在执行过程中可能会因为资源竞争、调度延迟、中断处理等因素而产生不同的执行路径和结果。这些因素在每次执行时都可能不同,从而导致程序结果的不可再现性。

    综上所述,程序并发执行时失去封闭性和可再现性主要是由于资源共享性、程序执行的随机性以及并发执行环境中的一些固有特性所导致的。这些特性使得并发程序在执行过程中受到多种因素的影响,从而导致结果的不可预测性和不可再现性。

  • 在操作系统中为什么要引入进程的概念?它会产生什么样的影响?

    在操作系统中引入进程的概念,主要是为了更好地管理系统资源、提高系统的并发性和效率,以及增强系统的稳定性和安全性。以下是关于引入进程概念的原因及其产生的影响的详细解释:

    引入进程概念的原因:

    1. 资源管理

      • 在多任务操作系统中,多个程序需要同时运行,每个程序都需要占用一定的系统资源(如CPU、内存、I/O设备等)。通过引入进程的概念,操作系统可以为每个程序分配独立的资源空间,避免程序之间的资源竞争和冲突,从而提高系统的资源利用率和效率。

    2. 并发执行

      • 进程的引入使得操作系统可以同时处理多个任务,即实现并发执行。这不仅可以提高系统的吞吐量,还可以增强用户体验。例如,在操作系统中同时运行多个应用程序,每个应用程序都可以作为一个独立的进程来执行。

    3. 系统稳定性

      • 进程之间是相互独立的,一个进程的崩溃不会影响其他进程的正常运行。这有助于增强系统的稳定性和可靠性。

    4. 安全性

      • 操作系统可以为每个进程分配独立的权限和资源,从而防止恶意程序的攻击和破坏。这种隔离机制有助于提高系统的安全性。

    引入进程概念产生的影响:

    1. 提高系统并发性和效率

      • 进程的引入使得操作系统可以同时运行多个程序,提高了系统的并发性和效率。这有助于充分利用系统资源,提高系统的吞吐量。

    2. 实现资源分配和调度

      • 操作系统通过进程来管理和分配系统资源。每个进程都有自己的资源空间和权限,操作系统可以根据进程的优先级、资源需求等信息进行调度,确保系统资源的合理分配和利用。

    3. 保证程序独立性

      • 进程之间是相互独立的,它们之间不会相互干扰。这有助于保护程序的完整性和安全性,防止一个程序的错误或崩溃影响其他程序的正常运行。

    4. 增强系统可扩展性

      • 进程的引入使得操作系统可以更容易地添加新的功能和模块。每个新功能或模块都可以作为一个独立的进程来运行,从而方便系统的扩展和维护。

    综上所述,引入进程的概念对操作系统产生了深远的影响。它不仅提高了系统的并发性和效率,还增强了系统的稳定性和安全性。同时,进程的概念也为操作系统的进一步发展和扩展提供了坚实的基础。

  • 试从动态性、并发性和独立性上比较进程和程序。

    从动态性、并发性和独立性上比较进程和程序,可以归纳如下:

    动态性:

    • 程序:程序是一组指令或代码的集合,用于执行特定任务或实现特定功能。程序在编译或解释后,其内容不会改变,因此程序是静态的。它只有在被加载到内存中运行时,通过进程这个载体,才表现出动态性。但需要注意的是,这里的“动态性”并非指程序本身具有动态性,而是指程序通过进程执行时展现出的动态行为。

    • 进程:进程是程序在执行时创建的实例,它包含了程序的指令和代码,以及正在运行的数据和状态。进程是动态的,因为它的状态随着执行而变化。进程可以在执行过程中被创建、删除、暂停、恢复和终止。

    并发性:

    • 程序:程序本身不具有并发性。在单处理器系统中,程序只能依次执行,无法同时运行。要实现程序的并发执行,需要通过操作系统的调度机制,将程序分割成多个进程或线程,并分配给不同的处理器或处理器时间片来执行。

    • 进程:进程是操作系统资源分配的最小单位,具有独立的内存空间和系统资源。因此,进程支持并发执行。在多处理器系统中,多个进程可以同时运行;在单处理器系统中,虽然每个时刻只能有一个进程在执行,但操作系统可以通过时间片轮转等方式,使得多个进程在宏观上看起来像是同时运行的。

    独立性:

    • 程序:程序本身不具有独立性。它需要依赖于操作系统的支持才能运行。程序在执行过程中,需要操作系统提供资源(如内存、I/O设备等)和调度服务。

    • 进程:进程具有较强的独立性。它是操作系统资源分配和调度的独立单位。每个进程都有自己的地址空间和系统资源,可以独立地运行、调度和结束。进程之间的相互独立,互不干扰,这有助于增强系统的稳定性和安全性。

    综上所述,进程和程序在动态性、并发性和独立性方面存在明显的区别。进程是程序在执行时的动态实例,具有动态性、并发性和独立性等特点;而程序则是一组静态的指令或代码集合,需要依赖于操作系统的支持才能运行。

  • 试说明PCB的作用具体表现在哪几个方面?为什么说PCB是进程存在的唯一标志?

    PCB(Process Control Block,进程控制块)在操作系统中扮演着至关重要的角色,其作用具体表现在以下几个方面:

    PCB的作用:

    1. 存储进程信息:

      • PCB中包含了描述进程状态和控制进程运行所需的全部信息,如进程标识符、进程状态、程序计数器、寄存器内容、内存管理信息等。这些信息是操作系统管理和调度进程的基础。

    2. 支持进程调度:

      • 操作系统通过PCB中的信息来选择合适的进程进行调度。例如,根据进程的优先级、等待时间、资源需求等因素,操作系统可以决定哪个进程应该获得CPU资源。

    3. 实现进程同步与通信:

      • PCB中的某些信息(如信号量、消息队列等)可以用于实现进程间的同步与通信。这有助于协调多个进程的执行,确保它们按照预定的顺序和方式相互协作。

    4. 记录进程历史:

      • PCB还记录了进程的历史信息,如进程创建时间、执行时间、等待时间等。这些信息对于性能分析、故障排查等方面具有重要意义。

    PCB是进程存在的唯一标志的原因:

    1. 唯一性:

      • 每个进程在系统中都有一个唯一的PCB与之对应。PCB中的进程标识符(PID)是区分不同进程的关键。因此,通过PCB可以唯一地确定一个进程的存在。

    2. 完整性:

      • PCB中包含了描述进程所需的所有信息,这些信息是操作系统管理和调度进程所必需的。如果缺少了PCB,操作系统将无法有效地管理和调度进程。

    3. 持久性:

      • PCB在进程的生命周期内始终存在,并随着进程的创建而创建,随着进程的终止而销毁。因此,PCB的存在与否直接反映了进程的存在状态。

    综上所述,PCB在操作系统中起着至关重要的作用,它不仅是存储进程信息、支持进程调度、实现进程同步与通信和记录进程历史的关键数据结构,还是进程存在的唯一标志。通过PCB,操作系统可以全面地管理和调度进程,确保系统的稳定性和高效性。

  • PCB提供了进程管理和进程调度所需要的哪些信息?

    PCB(Process Control Block,进程控制块)提供了进程管理和进程调度所需的关键信息,这些信息可以归纳为以下几个方面:

    进程管理所需信息:

    1. 处理机状态信息:

      • 通用寄存器:存储进程执行过程中用到的各种寄存器值,包括数据寄存器、地址寄存器等。

      • 指令寄存器:存储当前正在执行的指令的地址或指令本身。

      • 程序状态字(PSW):包含进程的状态信息,如当前指令的执行结果、中断标志、条件码等。

      • 用户栈指针:指向用户栈的栈顶,用于存储用户级数据和函数调用信息等。

    2. 进程控制信息:

      • 程序和数据的地址:指向进程的程序代码和数据在内存中的位置。

      • 资源清单:记录进程所占用的资源情况,如内存、文件、设备等。

      • 进程同步和通信机制:如信号量、消息队列等,用于实现进程间的同步与通信。

      • 链接指针:用于将PCB链接成链表,方便管理。

    进程调度所需信息:

    1. 进程状态:标识进程当前所处的状态,如就绪、运行、阻塞、挂起等。这是进程调度的重要依据。

    2. 进程优先级:表示进程在调度时的优先级顺序。优先级高的进程更容易获得CPU资源。

    3. 事件:记录与进程相关的事件信息,如I/O操作完成、定时器超时等。这些事件可以触发进程状态的改变和调度决策。

    4. 其他调度信息:如进程等待CPU的时间总和、进程已占用的CPU时间等,用于计算进程的调度权重和进行负载均衡等。

    综上所述,PCB为进程管理和进程调度提供了全面的信息支持,确保了操作系统的稳定性和高效性。通过PCB,操作系统可以准确地了解每个进程的状态和需求,从而进行合理的资源分配和调度决策。

  • 进程控制块的组织方式有哪几种?

    进程控制块(PCB,Process Control Block)的组织方式主要有以下几种:

    一、线性方式(线性表)。

    • 特点:所有的PCB被存储在一个线性数组中,每个进程对应数组中的一个元素。操作系统通过遍历线性表来查找、调度进程。

    • 优点:结构简单,易于实现。遍历线性表能够对进程进行顺序访问,方便进行批量操作(如全局调度)。

    • 缺点:查找效率低下,尤其是在系统进程数多时,需要遍历整个表。插入、删除操作需要移动其他元素,影响效率。

    二、链接方式(链接队列)。

    • 特点:PCB通过链表组织,每个PCB包含指向下一个进程控制块的指针,形成一个链表。可以按不同的状态(如就绪、阻塞等)将进程的PCB分别组织成不同的链表。

    • 优点:插入和删除操作效率较高,因为只需要调整指针。适合多种进程状态的分离管理(例如就绪队列、阻塞队列等)。

    • 缺点:查找效率较低,尤其在需要遍历整个链表时。链表操作较线性表复杂,需要维护指针。

    三、索引方式(索引表)。

    • 特点:系统根据所有进程的状态建立若干索引表,例如就绪索引表、阻塞索引表等,并把各索引表在内存的首地址记录在内存的一些专用单元中。在每个索引表的表目中,记录具有相应状态的某个PCB在PCB表中的位置。

    • 优点:通过索引表可以快速定位到具有特定状态的进程PCB,提高了查找效率。

    • 缺点:需要额外的索引表来维护,增加了系统的复杂性。同时,当进程状态发生变化时,需要更新索引表,增加了系统的开销。

    四、多级队列组织方式。

    • 特点:将进程根据优先级、状态等划分为多个队列,每个队列保存相同类型或优先级的进程PCB。常见的队列有就绪队列、阻塞队列、等待I/O队列等。每个队列可以使用链表或其他结构实现。

    • 优点:通过多级队列可以实现不同优先级进程的调度策略。分类管理不同状态的进程,便于系统调度和资源分配。插入、删除效率高,方便操作。

    • 缺点:多级队列结构相对复杂,需要根据进程的状态和优先级进行分类管理。需要维护多个队列,增加了管理成本。

    五、哈希表组织方式。

    • 特点:使用哈希函数将PCB存储在一个哈希表中,通过进程ID或其他标识符对PCB进行快速查找。

    • 优点:查找效率高,能够快速定位进程。适合用于进程数目较多的系统。

    • 缺点:需要额外计算哈希值,并处理哈希冲突。哈希表的插入、删除操作可能会导致一定的开销。

    六、树形组织方式。

    • 特点:将PCB按照某种层次关系组织成树形结构。常见的树形结构有进程父子关系树或其他按进程类型划分的树。每个PCB可能包含指向父进程和子进程的指针。

    • 优点:适合表示进程间的层次关系,如父子进程。便于管理具有父子关系的进程,尤其是进程终止时能够快速清理子进程。

    • 缺点:树形结构较为复杂,增加了管理和维护的成本。查找特定进程可能需要遍历整个树,效率较低。

    综上所述,不同的PCB组织方式各有优缺点,操作系统通常根据系统规模、进程数目及调度要求选择合适的PCB组织方式。

  • 何谓操作系统内核?内核的主要功能是什么?

    操作系统内核是操作系统的核心部分,它负责管理和控制计算机系统的所有硬件和软件资源。内核的主要功能包括以下几个方面:

    1. 提供硬件抽象层:内核为上层应用程序提供了一个简洁、统一的硬件接口,隐藏了底层硬件的复杂性和差异性。这样,应用程序就可以通过系统调用等接口与硬件进行交互,而无需关心底层硬件的具体实现。

    2. 进程管理:内核负责进程的创建、撤销、调度和同步等。它维护了一个进程控制块(PCB)的集合,用于记录每个进程的状态、优先级、内存地址等信息。通过调度算法,内核可以合理地分配CPU资源给各个进程,确保系统的并发性和效率。

    3. 内存管理:内核负责内存的分配、回收和保护等工作。它为用户进程分配虚拟地址空间,并通过页表等机制将虚拟地址映射到物理地址。此外,内核还提供了内存保护机制,防止用户进程访问非法内存区域。

    4. 文件管理:内核提供了对文件系统的支持,包括文件的创建、删除、读写和目录管理等。它维护了一个文件描述符表,用于记录每个进程打开的文件及其相关信息。通过文件系统,用户可以方便地存储和访问数据。

    5. 设备管理:内核负责管理各种输入输出设备,包括字符设备、块设备和网络设备等。它提供了设备驱动程序接口,允许设备驱动程序与硬件进行交互。通过设备管理,内核可以实现对设备的控制、数据传输和状态监测等功能。

    6. 中断处理:中断是CPU与外部设备或进程间进行通信的一种重要机制。内核负责处理各种中断请求,包括时钟中断、I/O中断等。当中断发生时,内核会暂停当前执行的进程,转而执行中断处理程序,处理完中断后再恢复原来进程的执行。

    此外,内核还具有时钟管理、原语操作等功能,这些功能共同支持着操作系统的正常运行。内核的设计和实现方式因操作系统而异,常见的内核类型包括宏内核、微内核、混合内核等。不同类型的内核在结构、功能和性能上有所差异,但都具有上述的基本功能。

  • 试说明进程在三个基本状态之间转换的典型原因。

    进程在运行过程中,由于各种资源和事件的影响,会在不同的状态之间转换。进程的三个基本状态是执行状态(也称为运行状态)、就绪状态和阻塞状态。以下是进程在这三个基本状态之间转换的典型原因:

    1. 就绪状态到执行状态:

    • 典型原因:当进程调度程序为之分配了处理器(CPU)后,该进程便由就绪状态转变为执行状态。此时,进程获得了所需的CPU资源,开始执行其程序代码。

    2. 执行状态到就绪状态:

    • 典型原因

      • 时间片用完:在分时系统中,每个进程被分配一个固定的时间片来执行。当时间片用完时,即使进程尚未执行完毕,也会被暂停执行,并返回到就绪状态,等待下一次被调度执行。

      • 更高优先级进程抢占:在抢占调度方式中,如果有更高优先级的进程需要运行,当前执行的进程可能会被强制让出CPU,并返回到就绪状态。

    1. 执行状态到阻塞状态:

    • 典型原因:正在执行的进程因发生某事件而无法继续执行,如等待I/O操作的完成、申请不到所需的系统资源(如内存、文件锁等)或访问已被占用的临界资源等。此时,进程会放弃CPU资源,并进入阻塞状态。在阻塞状态下,进程无法继续执行,直到所等待的事件完成或资源得到释放。

    4. 阻塞状态到就绪状态:

    • 典型原因:当阻塞进程所等待的事件完成时(如I/O操作已完成、获得了所需的资源或临界资源被释放等),该进程便由阻塞状态转变为就绪状态。此时,进程已经准备好再次被调度执行。

    综上所述,进程在三个基本状态之间的转换是由多种资源和事件共同影响的。这些转换确保了操作系统能够高效地管理和调度进程,以充分利用系统资源并满足用户的需求。

  • 为什么要引入挂起状态?该状态有哪些性质?

    引入挂起状态主要是出于以下几种需要:

    1. 对换的需要:为了缓和内存紧张的情况,操作系统可能会将内存中处于阻塞状态的进程换至外存上,使进程处于一种有别于阻塞状态的新状态,即挂起状态。即使该进程所期待的事件发生,由于它已被换出内存,该进程仍不具备执行条件而不能进入就绪队列。

    2. 终端用户的请求:当终端用户在自己的程序运行期间发现有可疑问题时,可能希望使自己的进程暂停下来,以便研究其执行情况或对程序进行修改。此时,用户可以使正在执行的进程暂停执行,若是就绪进程,则不接受调度,这种静止状态也称为挂起状态。

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

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

    5. 操作系统的需要:操作系统有时希望挂起某些进程,以便检查运行中的资源使用情况或进行记账。

    挂起状态具有以下性质:

    1. 挂起是进程从内存到外存的一种迁移:被挂起的进程会被暂时淘汰出内存,存放到外存(如磁盘)上。当条件允许时,该进程会被操作系统再次调回内存,重新进入等待被执行的状态,即就绪态。

    2. 挂起状态不参与进程调度:不论进程处于挂起就绪状态还是挂起阻塞状态,该进程都是不可能被调度而执行的。这意味着,在挂起状态下,进程不会占用CPU资源。

    3. 挂起条件与阻塞条件无关:对于处于挂起阻塞状态的进程,其阻塞条件(如等待I/O操作完成)与挂起条件(如内存不足导致进程被换出)是无关的。当进程所期待的事件出现后(如I/O操作完成),进程虽不再被阻塞,但仍可能因挂起条件未满足而不能运行。此时,应将该进程从挂起阻塞状态转换为挂起就绪状态。

    引入挂起状态有助于操作系统更有效地管理进程和资源,提高系统的稳定性和性能。

  • 在进行进程切换时,所要保存的处理机状态信息有哪些?

    在进行进程切换时,所要保存的处理机状态信息主要包括以下几个方面:

    1. 通用寄存器内容:通用寄存器是处理器中用于存储临时数据、操作数和操作结果的寄存器。在进程切换时,需要保存当前进程中所有通用寄存器的值,以便在恢复该进程时能够继续从上次停止的地方执行。

    2. 指令寄存器内容:指令寄存器存储了当前正在执行的指令的地址或指令本身。在进程切换时,需要保存指令寄存器的值,以便在恢复进程时能够继续执行正确的指令。

    3. 程序状态字(PSW):程序状态字包含了进程的状态信息,如当前指令的执行结果、中断标志、条件码等。这些信息对于恢复进程的执行状态至关重要。

    4. 用户栈指针:用户栈指针指向用户栈的栈顶,用于存储用户级数据和函数调用信息等。在进程切换时,需要保存用户栈指针的值,以便在恢复进程时能够正确访问用户栈中的数据。

    5. 程序计数器(PC):程序计数器存储了下一条将要执行的指令的地址。在进程切换时,需要保存程序计数器的值,以便在恢复进程时能够继续执行下一条指令。

    6. 浮点寄存器:如果处理器支持浮点运算,那么浮点寄存器也需要被保存。浮点寄存器用于存储浮点数的运算结果和中间值。

    7. 状态寄存器:状态寄存器包含了处理器的状态信息,如当前的工作模式、中断使能位等。这些信息对于恢复处理器的状态也是必要的。

    此外,在进行进程切换时,还可能需要保存一些与进程相关的其他信息,如内存管理信息(如页表、段表等)、进程控制信息(如进程ID、优先级、状态等)以及进程间通信和同步机制的相关信息。这些信息有助于操作系统在恢复进程时能够正确地重建进程的执行环境。

    综上所述,在进行进程切换时,需要保存的处理机状态信息包括通用寄存器、指令寄存器、程序状态字、用户栈指针、程序计数器、浮点寄存器以及状态寄存器等。这些信息共同构成了进程的上下文,是操作系统在恢复进程时所需要的重要信息。

  • 试说明引起进程创建的主要事件。

    引起进程创建的主要事件有以下几种:

    1. 系统初始化:在操作系统启动时,会创建一系列初始进程,这些进程负责系统的基本功能和服务的启动。这些进程通常是系统进程或守护进程,它们在后台运行,为用户提供服务或管理系统资源。

    2. 用户登录:当用户通过终端或图形用户界面登录到系统时,系统会为用户创建一个进程。这个进程被称为用户进程,它代表用户在系统中执行命令和应用程序。

    3. 系统服务请求:操作系统为了提供某项服务,可能会创建新的进程。例如,当系统接收到一个打印请求时,可能会创建一个打印进程来处理该请求。这种进程创建方式通常是由系统内部的事件触发的,用于响应用户的请求或系统的需求。

    4. 应用请求:用户程序在执行过程中,可能需要创建新的进程来协助其完成任务。例如,一个Web服务器可能会创建多个子进程来处理并发连接。这种进程创建方式是由用户程序内部的事件触发的,用于实现程序的功能或提高程序的并发性能。

    5. 批处理作业初始化:在批处理系统中,作业调度程序会根据输入队列中的作业创建相应的进程。这些进程负责执行作业中的命令和程序,并在作业完成后终止。批处理作业通常用于非交互式计算任务,如数据处理、科学计算等。

    此外,还有一些其他情况也可能导致进程的创建,例如系统内部的定时任务、进程间的通信和同步机制等。然而,这些事件通常不是进程创建的主要事件,而是在特定情况下触发的辅助事件。

    总的来说,引起进程创建的主要事件包括系统初始化、用户登录、系统服务请求、应用请求和批处理作业初始化等。这些事件共同构成了操作系统中进程创建的主要来源。

  • 试说明引起进程被撤消的主要事件。

    引起进程被撤销的主要事件有以下几种:

    1. 进程正常结束

      • 当一个进程完成了其预定的任务或执行到了程序的末尾时,它会正常结束。此时,操作系统会撤销该进程,并回收其所占用的资源。

    2. 进程异常结束

      • 在进程运行期间,可能会遇到各种错误或故障,导致进程异常结束。这些错误或故障包括但不限于越界错误(如访问非法内存地址)、保护错(如尝试执行特权指令)、非法指令(如执行未定义的指令)、特权指令错(如普通用户进程尝试执行特权指令)、运行超时(如进程在规定的时间内未完成其任务)、等待超时(如进程等待某个事件或资源的时间过长)、算术运算错(如执行非法的算术运算,如除以零)、I/O故障(如输入输出设备故障导致进程无法继续执行)。

    3. 外界干预

      • 操作系统或操作员可能会出于某种原因干预进程的执行,导致进程被撤销。这些原因包括但不限于操作员手动终止进程、操作系统为了解除死锁而撤销进程、父进程请求撤销其子进程(如父进程在终止时请求操作系统撤销其所有子进程)、操作系统为了维护系统稳定性或性能而撤销某些进程。

    综上所述,引起进程被撤销的主要事件包括进程正常结束、进程异常结束以及外界干预。这些事件共同构成了操作系统中进程撤销的主要来源。在实际操作中,操作系统会根据这些事件的具体情况和系统的需求来合理地撤销进程,并回收其所占用的资源。

  • 在创建一个进程时所要完成的主要工作是什么?

    在创建一个进程时,操作系统需要完成一系列主要工作,以确保新进程能够正确地被创建并在系统中运行。这些工作主要包括以下几个方面:

    1. 为新进程分配内存空间

      • 操作系统需要为新进程分配一定的内存空间,用于存储进程的代码、数据、堆栈等信息。这是新进程运行的基础。

    2. 初始化进程控制块(PCB)

      • 每个进程都有一个唯一的进程控制块(PCB),用于存储进程的各种信息,如进程ID、状态、优先级、寄存器值、堆栈指针等。

      • 在创建新进程时,操作系统需要为新进程初始化一个PCB,并将其插入到系统的进程队列中,以便进行管理和调度。

    3. 加载程序代码

      • 操作系统需要将新进程的可执行文件从磁盘或其他存储设备加载到内存中,并进行必要的链接和重定位操作,以确保程序代码能够正确执行。

    4. 初始化进程环境

      • 为新进程创建一个执行环境,包括设置进程的权限、资源限制、文件描述符等。这些设置有助于确保新进程在系统中安全运行。

    5. 设置进程上下文

      • 操作系统需要为新进程设置上下文环境,包括清空寄存器、设置堆栈指针等,以确保新进程在获得CPU控制权时能够正确执行。

    6. 启动进程执行

      • 当新进程准备好后,操作系统需要将其添加到就绪队列中,并等待合适的时机将CPU的控制权交给新进程,使其开始执行。

    7. 进程调度

      • 操作系统需要根据进程的优先级和其他调度算法来决定何时运行该进程,以及何时将控制权交给其他进程。这是确保系统高效运行的关键。

    此外,在创建进程时,操作系统还可能需要为新进程分配其他资源,如文件描述符、设备驱动程序等,以满足其运行需求。

    综上所述,创建一个进程时,操作系统需要完成内存分配、PCB初始化、程序代码加载、进程环境初始化、上下文设置、进程启动和调度等一系列工作。这些工作的完成可以确保新进程能够正确地被创建并在系统中高效运行。

  • 在撤消一个进程时所要完成的主要工作是什么?

    在撤销一个进程时,操作系统需要完成一系列主要工作,以确保系统资源的正确回收和进程状态的正确更新。这些工作主要包括以下几个方面:

    1. 检索进程控制块(PCB)

      • 根据被终止进程的标识符,从系统的PCB集中检索出该进程的PCB。PCB中包含了进程的各种状态信息和资源占用情况。

    2. 终止进程执行

      • 如果被终止的进程处于执行状态,操作系统需要立即终止其执行。这通常通过设置相应的状态标志或发送中断信号来实现。

    3. 处理子孙进程

      • 如果被终止的进程有子进程或子孙进程,操作系统需要确保这些进程也被正确终止,以防止它们成为不可控的“僵尸”进程。这通常通过递归地终止所有子孙进程来实现。

    4. 回收资源

      • 操作系统需要回收被终止进程所占用的全部资源,包括内存、文件描述符、设备驱动程序等。这些资源将被归还给父进程或系统,以便其他进程使用。

    5. 更新PCB状态

      • 将被终止进程的PCB从系统的进程队列或列表中移出,并更新其状态为“已终止”或“已回收”。这有助于操作系统正确地跟踪和管理进程的状态。

    6. 调用进程调度程序

      • 在回收完资源并更新PCB状态后,操作系统需要调用进程调度程序,重新选择一个进程占用CPU。这有助于确保系统的负载均衡和高效运行。

    综上所述,撤销一个进程时,操作系统需要完成检索PCB、终止进程执行、处理子孙进程、回收资源、更新PCB状态和调用进程调度程序等一系列工作。这些工作的完成可以确保系统资源的正确回收和进程状态的正确更新,从而维护系统的稳定性和性能。

  • 试说明引起进程阻塞或被唤醒的主要事件是什么?

    引起进程阻塞或被唤醒的主要事件包括以下几种:

    引起进程阻塞的事件:

    1. 请求系统服务

      • 当正在执行的进程请求系统提供服务(如I/O操作、文件访问、网络通信等),而系统暂时无法满足其请求时,进程会进入阻塞状态,等待系统服务的释放。

    2. 启动某种操作

      • 进程启动某种需要等待完成的操作(如磁盘读写、网络数据传输等)后,会进入阻塞状态,等待该操作完成。

    3. 新数据尚未到达

      • 在生产者-消费者模型中,消费者进程可能会因为等待生产者进程提供的新数据而阻塞。当新数据尚未到达时,消费者进程会处于阻塞状态。

    4. 无新工作可做

      • 某些系统进程(如某些类型的服务器进程)在没有新工作可做时,可能会选择阻塞自己,以节省系统资源。当有新的工作请求到达时,这些进程会被唤醒并继续执行。

    引起进程唤醒的事件:

    1. 系统服务释放

      • 当系统服务(如I/O操作、文件访问等)完成后,系统会释放相应的资源,并唤醒等待该资源的进程。

    2. 操作完成

      • 当进程启动的某种操作(如磁盘读写、网络数据传输等)完成后,中断处理程序会唤醒等待该操作的进程。

    3. 新数据到达

      • 在生产者-消费者模型中,当生产者进程产生新数据并放入缓冲区后,会唤醒等待数据的消费者进程。

    4. 新工作请求到达

      • 当有新的工作请求到达时,系统会唤醒等待新工作的进程,并分配相应的资源供其执行。

    综上所述,引起进程阻塞或被唤醒的主要事件与进程对系统资源的请求、操作的完成情况以及新数据的到达等密切相关。这些事件共同决定了进程的执行状态和系统的资源分配情况。

  • 为什么要在OS中引入线程?

    在操作系统(OS)中引入线程的主要目的是为了提高系统的并发性能和减少程序在并发执行时所付出的时空开销。以下是引入线程的具体原因和带来的好处:

    一、提高并发性能:

    1. 线程作为调度单位

      • 在传统操作系统中,进程是独立调度和分派的基本单位。然而,进程切换涉及较大的上下文开销,包括内存地址空间、打开文件、信号量等资源的切换。

      • 引入线程后,线程成为系统调度的基本单位。线程切换时只需保存和设置少量寄存器内容,上下文开销远小于进程切换。这使得系统能够更高效地调度线程,提高并发性能。

    2. 同一进程内线程并发

      • 引入线程后,不仅进程之间可以并发执行,而且同一个进程内的多个线程也可以并发执行。这进一步提高了系统的并发性,使得多个任务能够同时执行,提高了系统的整体性能。

    二、减少时空开销:

    1. 资源共享

      • 进程是系统资源的拥有者,而线程本身并不拥有系统资源。线程仅拥有一点必不可少的能保证独立运行的资源,同时允许多个线程共享该进程所拥有的资源。

      • 这种资源共享机制减少了资源的重复分配和回收开销,提高了资源利用率。

    2. 线程间通信开销小

      • 同一进程内的各个线程共享内存地址空间,可以直接读写内存空间进行通信,无需操作系统干预。这降低了线程间通信的开销,使得线程间能够更高效地协作完成任务。

    三、其他好处:

    1. 提高响应速度

      • 由于线程切换开销小且能够并发执行多个任务,系统能够更快速地响应用户的请求和系统的变化。

    2. 利用多处理器系统

      • 在多处理器系统中,多个线程可以并发地在不同的处理器上执行,从而充分利用多处理器的计算能力。

    3. 简化程序设计

      • 线程提供了比进程更细粒度的并发控制手段,使得程序设计者能够更灵活地控制并发任务的执行。这有助于简化程序设计并提高程序的可维护性。

    综上所述,引入线程能够显著提高操作系统的并发性能、减少时空开销并带来其他诸多好处。因此,在现代操作系统中,线程已成为一种重要的并发执行机制。

  • 试说明线程具有哪些属性?

    线程作为操作系统中调度和分派的基本单位(在引入线程的操作系统中),具有多个关键属性。以下是对线程属性的详细说明:

    一、基本属性

    1. 线程ID

      • 每个线程都有唯一的标识符(ID),用于操作系统和程序内部对线程的识别和引用。线程ID在创建时由系统分配,且在整个线程生命周期内保持不变。

    2. 线程名称

      • 线程可以有一个名称,用于在调试、监控和日志记录等场景中方便地识别线程。线程名称可以由程序员在创建线程时指定,也可以在线程运行过程中动态修改。

    二、调度和资源属性

    1. 调度优先级

      • 线程具有调度优先级,用于决定线程在可运行线程队列中的相对位置。优先级越高的线程越有可能被调度器选中执行。然而,需要注意的是,线程优先级并不总是决定线程的实际执行顺序,因为调度器还可能考虑其他因素(如时间片、公平性策略等)。

    2. 地址空间资源

      • 同一进程的各线程共享同一地址空间,这意味着它们可以访问相同的内存区域和变量。这种共享机制简化了线程间的通信和数据共享。

    3. 栈尺寸和栈地址

      • 每个线程都有自己的栈(调用栈),用于存储函数调用时的局部变量、返回地址等信息。线程的栈尺寸和栈地址可以在创建时指定,也可以在运行时动态调整。栈尺寸的大小会影响线程的并发性能和资源占用情况。

    三、状态和执行属性

    1. 并发性

      • 线程是并发执行的基本单位。在同一进程中,多个线程可以并发执行,从而提高了系统的并发性能和响应速度。

    2. 分离状态

      • 线程可以处于分离状态(detached state),即线程在终止时不会保留其终止状态。当线程处于分离状态时,系统不会为其保留任何资源或状态信息,从而简化了线程的管理和回收过程。

    3. 可连接性

      • 与分离状态相对的是可连接状态(joinable state)。处于可连接状态的线程在终止时会保留其终止状态,直到其他线程通过调用特定的函数(如pthread_join)来连接并获取其终止状态为止。

    四、其他属性

    1. 守护线程

      • 在某些编程语言(如Java)中,线程还可以被设置为守护线程(daemon thread)。守护线程是一种特殊的线程,它不会阻止JVM(Java虚拟机)的退出。当JVM中只剩下守护线程时,JVM会立即退出。

    2. 线程组

      • 线程可以属于某个线程组(thread group)。线程组是一种用于组织和管理线程的机制,它允许程序员将多个线程组织在一起,并对其进行统一的管理和监控。

    综上所述,线程具有多个关键属性,这些属性共同决定了线程的行为和特性。了解这些属性有助于程序员更好地设计和实现并发程序,从而提高系统的性能和可靠性。

  • 试从调度性、并发性、拥有资源及系统开销方面对进程和线程进行比较。

    以下是从调度性、并发性、拥有资源及系统开销方面对进程和线程进行的详细比较:

    一、调度性

    • 进程:在传统的操作系统中,进程是独立调度和分派的基本单位。操作系统会根据进程的优先级、状态等因素来决定何时调度某个进程执行。

    • 线程:在引入线程的操作系统中,线程成为调度和分派的基本单位。由于线程切换开销较小(仅涉及少量寄存器内容的保存和设置),系统能够更高效地调度线程执行。因此,多线程环境下,线程的调度通常更为频繁。

    二、并发性

    • 进程:进程之间可以并发执行,即多个进程可以在同一时间段内交替执行。然而,由于进程切换开销较大,且进程间通信需要通过进程间通信机制(如管道、消息队列等),因此进程并发执行的效率相对较低。

    • 线程:线程之间也可以并发执行,且由于线程共享同一进程的地址空间和资源,线程间通信更加高效(如通过共享内存进行通信)。因此,多线程环境下,系统的并发性能更高,能够更有效地利用系统资源和提高系统吞吐量。

    三、拥有资源

    • 进程:进程是系统资源的拥有者。每个进程都有自己独立的地址空间、文件描述符、网络连接等资源。这些资源在进程创建时由系统分配,并在进程终止时由系统回收。

    • 线程:线程本身并不拥有系统资源(除了一点必不可少的资源,如线程控制块、栈等)。线程共享其隶属进程的地址空间和资源。因此,线程在访问资源时无需进行额外的资源分配和回收操作,从而提高了资源利用率和访问速度。

    四、系统开销

    • 进程:由于进程切换涉及较大的上下文开销(包括内存地址空间、打开文件、信号量等资源的切换),因此操作系统在创建、撤销或切换进程时需要付出较大的开销。

    • 线程:与进程相比,线程的创建、撤销或切换开销较小。这是因为线程切换时仅需保存和设置少量寄存器内容,而无需涉及大量资源的切换。因此,多线程环境下,系统能够更高效地管理线程,降低系统开销。

    综上所述,进程和线程在调度性、并发性、拥有资源及系统开销方面存在显著差异。进程作为系统资源的拥有者,具有独立的地址空间和资源;而线程作为调度和分派的基本单位,具有更高的并发性能和更低的系统开销。在实际应用中,应根据具体需求选择合适的并发执行机制。

  • 线程控制块TCB中包含了哪些内容?

    线程控制块(Thread Control Block,TCB)是与进程的控制块(PCB)相似的子控制块。TCB中通常包含以下关键内容:

    1. 线程标识符:用于唯一标识一个线程,确保线程在系统中的唯一性。

    2. 一组寄存器:主要包括通用寄存器、指令计数器(PC)以及用户栈指针等。这些寄存器用于保存线程的上下文信息,以便在线程切换时能够正确地恢复线程的执行状态。

    3. 线程运行状态:用于指示线程当前的状态,如可运行状态、阻塞状态、就绪状态等。这些状态信息有助于操作系统对线程进行调度和管理。

    4. 线程专有存储区:用于存放线程的局部变量、参数和返回值等私有数据。这些数据在线程的生命周期内有效,且对其他线程不可见。

    5. 信号屏蔽:用于指定线程对哪些信号进行屏蔽(即不处理)。这有助于线程在处理特定任务时避免被不必要的信号干扰。

    6. 堆栈指针:指向线程的堆栈顶部,用于指示线程的堆栈使用情况。堆栈是线程用于存储局部变量、函数调用和返回地址等信息的区域。

    7. 调度参数:包括线程的优先级、调度策略等。这些参数用于指导操作系统对线程进行调度,以确保系统的公平性和效率。

    8. 链接指针:用于将线程控制块链接在一起,形成线程队列或链表。这有助于操作系统对线程进行统一管理和调度。

    此外,TCB中还可能包含其他与线程管理相关的信息,如线程的创建时间、终止时间、所属进程标识等。这些信息有助于操作系统对线程进行更全面的管理和监控。

    综上所述,TCB是操作系统中用于管理和调度线程的重要数据结构,它包含了线程的各种状态信息和资源占用情况。通过维护TCB,操作系统能够高效地管理线程,确保系统的稳定性和性能。

  • 何谓用户级线程和内核支持线程?

    用户级线程和内核支持线程是操作系统中两种基本的线程模型,它们各自有不同的特点和适用场景。

    用户级线程(User-Level Thread)

    用户级线程是仅存在于用户空间中的线程,由用户程序(而非操作系统内核)创建和管理。这种线程的创建、撤销、线程之间的同步与通信等功能,都无需利用系统调用来实现,因此它们与内核无关。用户级线程通常比内核线程更轻量级,因为不需要内核的干预,其创建、切换和销毁通常比内核线程更快速。

    用户级线程的优点包括:

    1. 轻量级:由于不需要内核的支持,用户线程的创建和管理开销较低。

    2. 灵活性:用户线程的创建和销毁由用户程序控制,因此具有更大的灵活性。

    3. 跨平台:用户线程通常可以在不同的操作系统上运行,因为它们的管理和调度由用户程序库处理,而不是依赖于特定的内核实现。

    然而,用户级线程也存在一些缺点:

    1. 无法充分利用多核处理器:用户线程的并发性受限于关联的内核线程数量。如果只有一个内核线程,那么多个用户线程将不能真正并行执行。

    2. 有限的内核支持:某些操作需要内核的支持,如硬件中断处理和系统调用。用户线程在执行这些操作时可能会导致整个进程的阻塞。

    内核支持线程(Kernel-Level Thread)

    内核支持线程是在内核支持下运行的线程。这种线程的创建、撤销和切换等都是依靠内核,在内核空间中实现的。为每个内核支持线程设置了线程控制块,内核根据该控制块感知某线程的存在并实施控制。

    内核支持线程的优点包括:

    1. 并行执行:在多处理器系统中,内核能够同时调度同一进程中多个线程并行执行。

    2. 线程阻塞处理:如果进程中的一个线程被阻塞了,内核可以调度该进程中的其他线程占用处理器运行,也可以运行其他进程中的线程。

    3. 切换开销小:内核支持线程具有很小的数据结构和堆栈,线程的切换比较快,切换开销小。

    然而,内核支持线程也存在一些缺点:

    1. 模式切换开销大:线程的切换需要装换到内核态进行,系统开销大。

    2. 资源占用:由于内核支持线程的创建和管理需要内核的参与,因此相对于用户级线程,内核支持线程会占用更多的系统资源。

    在实际应用中,选择用户级线程还是内核支持线程,需要根据具体的应用场景和需求来决定。例如,对于需要高并发性能且对系统资源占用要求较低的应用,可以选择用户级线程;而对于需要充分利用多核处理器资源且对线程切换开销要求不高的应用,可以选择内核支持线程。

  • 试说明用户级线程的实现方法。

    用户级线程的实现方法主要依赖于用户空间的应用程序或用户级线程库,而不涉及操作系统内核。以下是用户级线程实现方法的关键点:

    一、线程管理

    用户级线程的创建、撤销、调度和管理完全由用户空间的应用程序或线程库负责。这包括线程的创建、销毁、线程间的同步与通信等功能,这些操作都不需要利用系统调用来实现。

    二、线程库

    应用程序通过使用线程库来设计成多线程程序。线程库提供了一系列用于线程管理的API,如线程的创建、销毁、挂起、恢复等。这些API使得应用程序能够方便地管理和控制线程。

    三、线程切换

    用户级线程的切换是在用户空间完成的,因此切换的开销通常比内核级线程低。由于线程在进程内切换的规则远比进程调度和切换的规则简单,用户级线程的切换不需要进行用户态/核心态切换,从而提高了切换效率。

    四、线程上下文

    用户级线程驻留在用户空间,每个线程并不具有自身的线程上下文(如寄存器集、程序计数器等)。因此,对于操作系统来说,用户级线程是不可见的,也就是说,操作系统无法直接调度用户级线程到处理器内核上执行。

    五、多对一模型

    在用户级线程的实现中,通常采用多对一模型,即多个用户级线程映射到一个内核级线程(或称为轻量级进程LWP)。这意味着,虽然操作系统无法直接感知到用户级线程的存在,但可以通过内核级线程来间接地管理这些线程。当一个用户级线程需要执行时,它会被映射到相应的内核级线程上,由内核级线程来代表它执行。

    六、优点与限制

    用户级线程的优点包括:

    • 轻量级:由于不需要内核的支持,用户线程的创建和管理开销较低。

    • 快速切换:用户级线程的切换是在用户空间完成的,因此切换速度快。

    • 灵活性:用户线程的创建和销毁由用户程序控制,因此具有更大的灵活性。

    然而,用户级线程也存在一些限制:

    • 无法充分利用多核处理器:由于用户线程的调度由用户空间的线程库负责,它们通常无法充分利用多核处理器。

    • 阻塞问题:如果一个用户级线程阻塞,整个进程的执行也可能受到影响,因为进程是最小的调度单位。

    综上所述,用户级线程的实现方法主要依赖于用户空间的应用程序或线程库,并通过多对一模型与内核级线程进行映射。虽然用户级线程具有轻量级、快速切换和灵活性等优点,但也存在无法充分利用多核处理器和阻塞问题等限制。

  • 试说明内核支持线程的实现方法

    内核支持线程(Kernel Supported Threads)的实现方法主要涉及操作系统内核对线程的管理和支持。以下是内核支持线程实现方法的关键点:

    一、线程控制块(TCB)

    1. 分配与初始化:

      • 系统在创建新进程时,会为其分配一个任务数据区(PTDA),其中包含若干个线程控制块(TCB)空间。

      • 每当创建一个新线程时,系统会为其分配一个TCB,并将相关信息(如线程标识符、优先级、状态等)写入TCB。

    2. 管理与回收:

      • 当PTDA中的TCB用完,而进程又有新线程需要创建时,只要所创建的线程数目未超过系统允许值,系统可为新线程分配新的TCB。

      • 在撤销一个线程时,系统会回收该线程的所有资源和TCB。

    二、线程创建与撤销

    1. 线程创建:

      • 用户进程或系统进程通过系统调用请求创建新线程。

      • 内核响应系统调用,为新线程分配TCB和必要的资源(如堆栈空间)。

      • 内核将新线程的TCB加入进程的线程列表中,并设置线程的初始状态。

    2. 线程撤销:

      • 用户进程或系统进程通过系统调用请求撤销线程。

      • 内核响应系统调用,回收被撤销线程的所有资源和TCB。

      • 内核从进程的线程列表中删除被撤销线程的TCB。

    三、线程调度与切换

    1. 调度策略:

      • 内核根据线程的优先级、状态等因素,决定何时调度某个线程执行。

      • 在多处理器系统中,内核能够同时调度同一个进程中的多个线程并行执行。

    2. 线程切换:

      • 当需要切换线程时,内核会保存当前线程的上下文(如寄存器集、程序计数器等),并恢复下一个要执行的线程的上下文。

      • 线程切换涉及用户态/核心态的切换,但内核通过优化减少了这种切换的开销。

    四、线程同步与通信

    1. 同步机制:

      • 内核提供了一系列同步机制(如互斥锁、信号量等),用于保证线程间的同步执行。

      • 这些同步机制可以防止多个线程同时访问共享资源而导致的冲突。

    2. 通信机制:

      • 内核还提供了线程间的通信机制(如消息队列、管道等),用于线程间的数据传输和协作。

      • 这些通信机制使得线程能够方便地共享信息和协调执行。

    五、内核空间与用户空间的交互

    1. 系统调用:

      • 用户级线程通过系统调用与内核进行交互,请求内核提供的服务(如创建线程、撤销线程、同步与通信等)。

      • 内核通过系统调用接口接收用户级线程的请求,并为其提供服务。

    2. 上下文切换:

      • 当用户级线程执行系统调用时,需要从用户空间切换到内核空间进行处理。

      • 内核处理完系统调用后,再将控制权返回给用户级线程,此时需要从内核空间切换回用户空间。

    综上所述,内核支持线程的实现方法涉及线程控制块的分配与管理、线程的创建与撤销、线程的调度与切换、线程的同步与通信以及内核空间与用户空间的交互等多个方面。这些方法共同构成了操作系统内核对线程的支持和管理机制。

  • 多线程模型有哪几种类型?多对一模型有何优缺点?

    多线程模型主要有三种类型,包括多对一模型、一对一模型和多对多模型。下面将详细解释这三种模型,并重点分析多对一模型的优缺点。

    一、多线程模型类型

    1. 多对一模型

      • 特点:在这种模型中,多个用户级线程被映射到一个内核级线程(或称为轻量级进程,LWP)。线程管理是由用户空间的线程库来完成的,因此效率更高。

      • 示例:早期的Java版本和Solaris操作系统中的Green threads线程库就采用了这种模型。

    2. 一对一模型

      • 特点:在这种模型中,每个用户线程都被映射到一个内核线程。这种模型提供了更好的并发性,因为一个用户线程发起系统调用而阻塞时,允许另一个线程继续运行。

      • 优点:并发能力强,多线程可以在多核处理机上并行执行。

      • 缺点:由于需要为每个用户线程创建一个内核线程,因此线程创建的开销较大,且可能受到操作系统内核线程数量限制的影响。

    3. 多对多模型

      • 特点:在这种模型中,多个用户线程被映射到多个(但少于用户线程数量)内核线程上。这种模型结合了多对一模型和一对一模型的优点,既提供了较好的并发性,又降低了线程创建的开销。

      • 优点:开发人员可以创建任意多的用户线程,并且相应内核线程能在多处理器系统上并发执行。当一个线程执行阻塞系统调用时,内核可以调度另一个线程来执行。

      • 缺点:实现相对复杂,需要平衡用户线程和内核线程的数量以优化性能。

    二、多对一模型的优缺点

    1. 优点

      • 线程切换快速:由于多个用户线程共享一个内核线程,因此线程之间的切换可以在用户空间完成,无需切换到内核空间,从而提高了切换效率。

      • 资源占用少:相对于一对一模型,多对一模型减少了内核线程的数量,从而降低了系统资源的占用。

    2. 缺点

      • 并发性受限:由于多个用户线程共享一个内核线程,因此它们不能真正并行执行。在多处理器系统上,这种限制尤为明显,因为只有一个内核线程可以访问内核,导致处理器的增多并不能显著提高线程性能。

      • 阻塞问题:如果一个用户线程执行阻塞系统调用(如I/O操作),那么整个进程(包括其他用户线程)都会被阻塞,直到该线程完成阻塞操作。这降低了系统的响应性和吞吐量。

      • 无法充分利用多核处理器:由于多对一模型中的多个用户线程共享一个内核线程,因此它们无法充分利用多核处理器的并行处理能力。这限制了系统在高并发场景下的性能表现。

    综上所述,多线程模型中的多对一模型具有线程切换快速和资源占用少等优点,但也存在并发性受限、阻塞问题和无法充分利用多核处理器等缺点。因此,在选择多线程模型时,需要根据具体的应用场景和需求进行权衡和选择。


网站公告

今日签到

点亮在社区的每一天
去签到