《操作系统概念》笔记--第三章 进程

进程

进程概念

早期的计算机一次只能执行一个程序。这种程序完全控制系统,并且访问所有系统资源。相比之下,现在计算机系统允许加载多个程序到内存,以便并发执行。这就导致了进程(peocess)的产生。进程是现在分时系统的工作单元。
程序本身不是进程。程序只是被动(passive)实体,如存储在磁盘上包含一系列指令的文件(经常称为可执行文件(executable file))。
相反,进程是活动(active)实体,具有一个程序计数器用于执行下个执行命令和一组相关资源。

虽然两个进程可以与同一程序相关联,但是当做两个单独的执行序列。每个都是独立进程,因为文本段相同,但是数据,堆及堆栈却不同。

进程状态

进程在执行时会改变状态。共有五种状态:
新的(new):进程正在创建
运行(running):指令正在执行
等待(waiting):进程等待发生某个事件(如I/O完成或收到信号)
就绪(ready):进程等待分配处理器
终止(terminated):进程已经完成执行

一次只有一个进程在一个处理器上运行(running),但是许多进程可处于就绪(ready)或等待(waiting)状态。

进程控制块

操作系统的每个进程表示,采用进程控制块(Pocess Control Block ,PCB),也叫做任务控制块(task control block)。
它包含进程相关的七种信息:
进程状态(process state): 状态可以包括新的,运行,等待,就绪,终止
程序计数器(program counter):计数器表示程序将要执行的下个指令的地址。
CPU寄存器(CPU register):根据计算机体系结构的不同,寄存器的类型和数量也会不同。它们包括累加器,索引寄存器等等。
CPU调度信息(CPU-scheduling information):这类信息包括进程优先级,调度队列的指针和其他调度参数。
内存管理信息(memory-management information):这类系统可以包括基地址和界限寄存器的值,页表或段表等。
记账信息(accounting information):这类信息包括CPU时间,实际使用时间,时间期限,记账信息,作业或进程数量等。
I/O状态信息(I/O state information):这类信息包括分配给进程的I/O设备列表,打开文件列表等。

简而言之,PCB简单地作为这些信息的仓库,这些信息随着进程的不同而不同。

进程调度

多道程序设计的目标是,无论何时都有进程运行,从而最大化CPU利用率。
进程调度器(process scheduler)选择一个可用进程到CPU上执行。
单处理器系统不会具有多个正在运行的进程。如果有多个进程,那么余下的需要的等待CPU空闲并能重新调度。

调度队列

进程在进入系统时,会被加到作业队列(job queue),这个队列包括系统内的所有进程。
这个队列通常用链表实现,其头节点有两个指针,用于指向链表的第一个和最后一个PCB块;每个PCB还包括一个指针,指向就绪队列的下一个PCB。
系统还有其他队列。等待特定I/O设备的进程列表,成为设备队列(device queue)。每个设备都有自己的设备队列。
最初,新进程被加到就绪队列中,它在就绪队列中等待,知道被选中执行或被分派。
当该进程分配到CPU并执行时,有以下3种事件可能发生:
进程可能发出I/O请求,并被放到I/O队列中。
进程可能创建一个新的子进程,并等待其终止。
进程可能由于中断而被强制释放CPU,并被放回到就绪队列中。

前两种情况,进程最终从等待状态切换到就绪状态,并放回到就绪队列。进程重复这一循环直到终止。然后它就会从所有队列中删除,其PCB和资源也被释放。

调度程序

进程在整个生命周期中,会在各种调度队列之间迁移。操作系统为了按一定方式从这些队列中选择进程,进程选择通过适当调度器或调度程序(scheduler)来执行。
长期调度程序(long-term scheduler)从大容量存储设备(通常为磁盘)的缓冲池中选择进程,加到内存中,以便执行。短期调度程序(short-term scheduler)CPU调度程序(CPU scheduler)从准备执行的进程中选择进程,并分配给CPU。
从上面就很容易看出长期调度程序与短期调度程序的作用与区别。
其中,这两种调度程序的主要区别是执行效率。
短期调度程序必须经常为CPU选择新的进程。进程可能执行几毫秒,就会等待I//O请求。通常,短期调度程序每100ms至少执行一次。由于执行之间的时间短,短期调度程序必须快速。
而长期调度程序执行并不频繁,在新进程的创建之前,可能有几分钟的间隔。长期调度程序控制多道程序程度(degree of multiprogramming)(内存中的进程数量)。因此,只有在进程离开系统时,才需要长期调度程序的调度。由于每次执行之间的更长时间间隔,长期调度程序可以负担得起更多时间,以便决定选择执行那个进程。
重要的是,长期调度程序需要认真选择。
大多数进程可分为:I/O为主或CPU为主
I/O密集型进程(I/O-bound process),执行I/O比执行计算需要花费更多时间。相反,CPU密集型进程(CPU-bound process)很少产生I/O请求,而是将更多时间用于执行计算。所以,长期调度程序应该选择I/O密集型和CPU密集型的合理进程组合。

如果所有进程都是I/O密集型的,那么就绪队列几乎总是为空,从而短期调度程序没有什么可做。如果所有进程都是CPU密集型的,那么I/O等待队列几乎总是为空,从而设备没有得到使用,因而系统会不平衡。
所以,为了使得性能最佳,系统需要I/O密集型和CPU密集型的进程组合。
有的操作系统如分时系统,可能引入一个额外的中期调度程序(medium-term scheduler)。
中期调度程序的核心思想是可将进程从内存(或从CPU竞争)中移出,从而降低多道程序程度。之后,进程可被重新调入内存,并从中断处继续执行。这种方案称为交换(swap)。通过中期调度程序,进程可换出(swap out),并在后来可换入(swap in)。
为了改善进程组合,或者由于内存需求改变导致过度使用内存从而需要释放内存,就有必要使用交换

*论述长期调度 ,中期调度,短期调度的差异?

短期调度:短期调度在内存进程中选择就绪执行的进程加载到CPU
中期调度:中期调度将部分运行进程移出内存,之后又加载进程到内存,从中断处运行
长期调度:长期调度从大容量存储设备的缓冲池中选择进程加载到内存
他们的不同之处是他们执行的频率。短期调度程序需要经常调用,而长期调用并不频繁调用,可能在进程离开系统时才被唤起

上下文切换

切换CPU到另一个进程需要保存当前进程状态和恢复另一个进程的状态,这个任务称为上下文切换(context switch)。
中断导致CPU从执行当前任务改变到CPU上的进程的上下文,以便在处理后能够恢复上下文,即先挂起进程,再恢复进程。
进程上下文采用PCB表示,包括CPU寄存器的值,进程状态和内存信息管理等。
通常,通过执行状态保存(state save),保存CPU当前状态(包括内核模式和用户模式),之后,状态恢复(state restore)重新开始运行。
*内核采取一些动作以便在两个进程之间进行上下文切换,请描述一下?

操作系统保存正在运行的进程中的上下文,然后恢复将要运行进程的上下文

进程运行

大多数系统的进程能够并发执行,它们可以动态创建和删除。

进程创建

进程在执行过程中可能创建多个新的进程。创建进程称为父进程,而新的进程称为子进程。每个新进程可以在创建其他的进程,从而形成进程树(process tree)。
大多数的操作系统对进程的识别采用的是唯一的进程标识符(process identifier, pid),这通常是一个整数值。

系统内的每个进程都有唯一的pid,它可以用作索引,以便访问内核中的进程的各种属性。

一般来说,当一个进程创建子进程时,该子进程会需要一定的资源(CPU时间,内存等)来完成任务,有两种资源获得来源:
子进程可以从操作系统那里直接获得资源
也可以父进程那里获得资源子集。
除了提供各种物理和逻辑资源外,父进程也可能向子进程传递初始化数据(或输入)。
当进程创建新进程时,可有两种执行可能:
父进程与子进程并发执行
父进程等待,直到某个或全部子进程执行完
新进程的地址空间也有两种可能:
子进程是父进程的复制品
子进程加载另一个程序(如使用系统调用exec())

进程终止

当进程完成执行最后语句并且通过系统调用exit()请求操作系统删除自身时,进程终止。
父进程终止子进程的原因有很多,如以下三种
子进程使用了超过它所分配的资源(为判定是否发生这种情况,父进程应有一个机制,以检查子进程的状态)。
分配给子进程的任务,不再需要。
父进程正在退出,而且操作系统不允许无父进程的子进程继续执行。
级联终止
有些系统不允许子进程在父进程已终止的情况下存在。对于这类系统,如果一个进程终止,那么它的所有子进程也应终止。这种现象,就叫做级联终止。
当一个进程终止时,操作系统会释放其资源。

不过,它位于进程表中的条目还是在的,直到它的父进程调用wait(),这是因为进程表包含了进程的退出状态。
当进程已经终止,但是其父进程尚未调用wait(),这样的进程称为僵尸进程(zonbie process)。
所有进程终止时都会过度到这种状态,但是一般僵尸只是短暂存在。一旦父进程调用了wait(),僵尸进程的进程标识符和它在进程表中的条目就会释放。
如果父进程没有调用wait()就终止,子进程就会称为孤儿进程(orphan process)。

进程间通信

操作系统内的并发执行进程可以是独立的也可以是协作的。
如果一个进程不能影响其它进程或受其他进程影响,那么该进程是独立的。

显然,不与任何其他进程共享数据的进程是独立的。

如果一个进程能影响其他进程或受其他进程所影响,那么该进程是协作的。

显然,与其他进程共享数据的进程为协作进程

提供环境允许进程协作,有很多理由与好处,如以下四种
信息共享(information sharing):由于多个用户可能对同样的信息感兴趣(例如共享文件),所以应提供环境以允许并发访问这些信息。
计算加速(computation speedup):可以把一个任务分成多个子任务,每个子任务可以与其他子任务并发执行。
模块化(modulrity):可能需要按模块化方式构造系统,可将系统功能分成独立的进程或线程。
方便(convenience):即使单个用户也可能同时执行许多任务。
进程间通信(InterProcess Communication, IPC)机制 **
协作进程需要有一种
进程间通信(InterProcess Communication,IPC)机制,以允许进程相互交换数据与信息。
进程间通信有
两种**基本模型:
共享内存(shared memory)
消息传递(message passing)

共享内存会建立一块供协作进程共享的内存区域,进程通过向此共享区域读出与写入数据来交换信息
消息传递模型通过在协作进程间交换消息来实现通信

两者的比较:
消息传递对于交换较少数量的数据很有用,因为无需避免冲突。对于分布式系统,消息传递也比共享内存更易实现。
共享内存可以快于消息传递。这是因为消息传递实现经常采用系统调用,因此需要消耗更多时间以便内核介入。与此相反,共享内存系统仅在建立共享区域时需要调用系统调用,一旦建立共享内存,所有访问都可以作为常规内存访问,无需借助内核。

共享内存系统

采用共享内存的进程间通信,需要通信进程建立共享内存区域。
生产者-消费者问题
**生产者(producer)进程生产信息,以供消费者(consumer)**进程消费
解决生产者消费者的问题的方法之一是,采用共享内存。为了允许生产者进程和消费者进程并发执行,应有一个可用的缓冲区,以被生产者填充和被消费者清空。这个缓冲区驻留在生产者进程和消费者进程的共享区域内。当消费者使用一项时,生产者可产生另一项。

生产者和消费者必须同步,这样消费者和不会试图消费一个尚未生产出来的项。

缓冲区类型分为两种
无界缓冲区(unbounded-buffer):没有限制缓冲区的大小。

消费者不得不等待新的项,但生产者总是可以产生新项。

有界缓冲区(bounded-buffer):固定大小的缓冲区。

对于这种情况,如果缓冲区为空,那么消费者必须等待。如果缓冲区已满,那么生产者必须等待。

消息传递系统

操作系统提供机制,以便协作进程通过消息传递功能进行通信。
这有三种方法,用于实现链路和操作send()/receive():
直接或间接的通信
同步或异步的通信
自动或显式的缓冲

命名

直接通信(direct communication)
直接通信需要通信的每个进程必须明确指定通信的接收者或发送者。

send(p,message): 向进程P发送message
receive(Q,message):从进程Q接收message

这种方案具有以下三种属性:
在需要通信的每对进程之间,自动建立链路。进程仅需知道对方身份就可进行交流。
每个链路只与两个进程相关
每对进程之间只有一个链路

这种方案展示了寻址的对称性(symmetry),即发送和接收进程必须指定对方,以便通信。

下面一种采用寻址的非对称性(asymmetry),即只要发送者指定接收者,而接收者不需要指定发送者。

send(P,message):向进程P发送message
receive(id,message):从任何进程,接受message,这里变量id被设置成与其通信进程的名称。

这两个方案都有一定的缺点:生成进程定义的有限模块化。
更改进程标识符可能需要分析所有其他进程定义,所有旧的标识符的引用都应被找到,以便修改成为新标识符。
间接通信(indirect communication)
间接通信通过邮箱或端口来发送和接收消息。

邮箱可以抽象成一个对象,进程可以向其中存放消息,也可从中删除消息,每个邮箱都有一个唯一的标识符。

一个进程可以通过多个不同邮箱与另一个进程通信

send(A, message):向邮箱A发送message
receive(A, message):从邮箱A接受message

这种方案有以下三种特点:
只有在两个进程共享一个邮箱时,才能建立通信线路。
一个链路可以与两个甚至更多进程相关联。
两个通信进程之间可有多个不同链路,每个链路对应于一个邮箱
下面举一个问题:
假设进程P1,P2和P3都共享邮箱A,进程P1发送一个消息到A,而进程P2和P3都对A执行receive()。那么哪个进程会收到P1发送的消息?
答案不是唯一的,取决于所选择的方案:
允许一个链路最多与两个进程关联
允许一次最多一个进程执行receive()
允许系统随意选择一个进程以便接收消息(即P2和P3两者之一都可以接收消息,但不能两个都可以)

系统同样可以定义一个算法选择哪个进程是接收者,系统还可以让发送者指定接收者

邮箱可以为进程或操作系统拥有
如果邮箱为进程所拥有(即邮箱是进程地址空间的一部分),那么需要区分所有者和使用者。当拥有邮箱的进程终止,那么邮箱就会消失。任何进程后来向该邮箱发送消息,都会得知邮箱不存在。
如果邮箱为操作系统拥有,那么邮箱是独立的,他不属于某个特定进程。

同步

消息传递可以是阻塞(blocking)非阻塞(nonblocking),也称为同步(synchronous)异步(asynchronous)
发送接收有以下四种
阻塞发送(blocking send):发送进程阻塞,直到消息由接收进程或邮箱所接收
非阻塞发送(nonblocking send):发送进程发送消息,并且恢复操作,不会等待
阻塞接收(blocking receive):接收进程阻塞,直到有消息可用
非阻塞接收(nonblocking receive):接收进程收到一个有效消息或空消息

不同组合的send()和receive()都有可能

缓存

不管通信是直接的还是间接的,通信交换的消息总是驻留在临时队列中。也就是缓存
队列实现有三种方法:
零容量(zero capacity):队列的最大长度为0,因此,链路中不能有任何消息处于等待,这种情况下,发送者应该阻塞,直到接收者接收到消息。
有限容量(bounded capacity):队列长度为有限的n,因此最多只能有n个消息驻留其中,如果在发送新消息时队列未满,那么该消息可放在队列中,且发送者可以继续执行而不必等待。然而,链路容量有限,如果链路已满,那么发送者应该阻塞,知道队列空间有可用的为止。
无限容量(unbounded capacity):队列长度可以无限。因此,不管多少消息都可在其中等待。发送者从不阻塞。

总结与梳理

进程的概念和五种状态
PCB的概念与包含进程的七种信息
进程调度与三种调度程序
进程创建到结束的过程

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章