第二部分:进程管理

Posted 岳飞传

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第二部分:进程管理相关的知识,希望对你有一定的参考价值。

第二部分:进程管理

进程:进程可以看做正在执行的程序。进程需要一定的资源来完成更其任务。
进程是大多数系统中的工作单元。这样的系统有一组进程组成操作系统进程执行系统代码,用户进程执行用户代码,所有进程可以并发执行。

第三章: 进程

3.1 进程概念

程序是被动实体,进程是活动实体,它有一个程序计数器用来表示下一个要执行的命令和相关资源集合。

进程的状态

  1. 新的:进程正在被创建
  2. 运行:指令正在被执行
  3. 等待:进程等待某个事件的发生(如I/O完成或收到信号)
  4. 就绪:进程等待分配处理器
  5. 终止:进程完成执行

重要:一次只有一个进程可在一个处理器上运行,但是多个进程可处于就绪或等待状态。

进程块控制(process control block,PCB):每个进程在操作系统内用进程控制块来表示,其包含许多与一个特定进程相关的信息。

进程状态:状态可包括新的,就绪,运行,等待,停止
程序计数器:计数器表示进程要执行的下个指令的地址。
CPU寄存器:根据计算机结构体系的不同,寄存器的数量和类型也不同。他包括累计器,索引寄存器,堆栈指针,通用寄存器和其他条件码信息寄存器。
CPU调度信息:包括进程优先级,调度队列的指针等
内存管理信息:根据操作系统所使用的内存系统,该类信息包括基址和界限寄存器的值,页表或段表。
记账信息:包括CPU时间,实际使用时间,时间界限,记账数据,作业或进程数量
I/O状态信息:包括分配给进程I/O设备列表,打开的文件列表等等。

3.2 进程调度

多道程序设计的目的就是无论何时都有进程在运行,从而使CPU利用率达到最大。

进程调度:选择一个可用的进程到CPU上执行。

  1. 调度队列:进程进入系统时,会被加到作业队列中,该队列包括系统中的所有进程。驻留在内存中就绪的,等待运行的进程保存在就绪队列中。该队列通常用链表来实现,头结点指向链表的第一个个和最后一个PCB块的指针。每个PCB包含一个指向就绪队列的下一个PCB的指针域。

    等待特定I/O设备的进程列表称为设备队列。

    讨论进程调度的常用表示方法是队列图。

    当进程分配到CPU并执行时,可能发生的情形:

    • 进程可能发出一个I/O请求,并被放到I/O队列中。
    • 进程可能创建一个新的子进程,并等待期结束
    • 进程可能会由于中断而强制释放CPU,并被放回到就绪队列中。
  2. 调度程序

    长期调度程序(long-term scheduler) 或作业调度程序(job shceduler)从该池中选择进程,并装入内存以准备执行。

    短期调度程序(short-term scheduler)或CPU调度程序从准备执行的进程中选择进程并为之分配CPU.

    上下文切换:将CPU切换到另一个进程需要保存当前进程的状态并恢复另一个进程状态。

3.3 进程操作

  1. 进程创建

    进程在执行过程中,能通过创建进程系统调用创建多个新进程。大多数操作系统根据一个唯一标识符(process identifier,pid)来识别进程,pid通常是一个数值。

    当进程创建新进程时,有两种执行可能:

    1. 父进程与子进程并发执行
    2. 父进程等待,直到某个或全部子进程执行完毕

    并发和并行的区别:?

    新进程的地址空间也有两种可能:

    1. 子进程是父进程的复制品(具有与父进程相同的程序和数据)
    2. 子进程装入另一个新程序

在UNIX操作系统中,每个进程都有唯一的标识符。通过fork()系统调用,可创建新进程。新进程通过复制原来进程的地址空间而成。这种机制允许父进程与子进程方便的进行通信。两个进程(父进程和子进程)都继续执行位于系统调用fork()之后的指令。但是,有一点不同:对于新子进程,系统调用fork()的返回值为0;而对于父进程,返回值为子进程的进程标识符(非零)。

通常,在系统调用fork()之后,一个进程会使系统调用exec(),以用新程序来取代进程内存空间。系统调用exec()将二进制文件装入内存(消除了原来包含系统调用exec()的程序的内存映射),并开始执行。采用这种方式,两个进程能互相通信,并能按各自的方法执行。

  1. 进程终止

    当进程完成执行后最后的语句并系统调用exit()请求操作系统删除自身是,进程终止。这时,进程可以返回状态值(通常为整数)到父进程(通过系统调用wait())。

3.4 进程间通信(interprocess communication,IPC)

进程间的通信的两种基本模式:共享内存和消息传递

  1. 共享内存系统

    采用共享内存的进程间通信需要通信进程建立共享内存区域。通常,一块共享内存区域驻留在生成共享内存段进程的地址空间。其他希望使用这个共享内存段进行通信的进程必须将此放到他们自己的地址空间上。

eg: POSIX,表示可移植操作系统接口(Portable Operating System Interface ,缩写为 POSIX ),POSIX标准定义了操作系统应该为应用程序提供的接口标准,是IEEE为要在各种UNIX操作系统上运行的软件而定义的一系列API标准的总称,其正式称呼为IEEE 1003,而国际标准名称为ISO/IEC 9945。

POSIX标准意在期望获得源代码级别的软件可移植性。换句话说,为一个POSIX兼容的操作系统编写的程序,应该可以在任何其它的POSIX操作系统(即使是来自另一个厂商)上编译执行。

  1. 消息传递系统

    消息传递工具:发送消息,接收消息,通信线路

    1. 命名:直接通信,间接通信(邮箱)
    2. 同步:消息传递可以是阻塞或非阻塞(也称为同步或异步)
    3. 缓冲:不管通信是直接还是间接的,通信进程所交换的信息都驻留在临时队列中,简单的讲,队列实现有三种方法:

      零容量 :队列的最大长度为0;因此,线路中不能有任何消息处于等待。即必须阻塞发送,直到接收者接收到消息。

      有限容量:队列长度为有限的n;因此,最多只能有n个消息驻留在队列中,如果发送新消息是队列未满,那么该消息可以放在队列中(或者复制消息或者保存消息的指针),其发送者可以继续执行而不必等待。不过线路容量有限。如果线路满,则必须阻塞发送者直到队列中的空间可用为止。

      无限容量:队列长度可以无限,因此不管多少消息都可在其中等待,从不阻塞发送者。

eg: Mach [mɑk],Mach是一个由卡内基梅隆大学开发的用于支持操作系统研究的操作系统内核,是基于共享内存的 IPC系统.

第4章 线程

4.1 概述

线程:是CPU使用的基本单元,它由线程ID,程序计数器,寄存器集合和栈组成。它与属于统一进程的其他线程共享代码段、数据段和其他操作系统资源。

多线程的优点

  1. 响应度高
  2. 共享资源:默认共享他们所属进程的内存和资源。
  3. 经济:线程可以共享资源,创建和替换速度比进程块。
  4. 多处理体系结构的利用:能充分利用多处理器体系结构,以便每个进程能并行运行在不同的处理器上。

4.2 多线程模型

线程支持:用户层的用户线程和内核层的内核线程;

用户线程和内核线程之间的关系模型:

  1. 多对一模型:将许多用户级线程映射到一个内核线程。线程管理是在用户空间进行的,因而效率比较高。但是如果一个线程执行了阻塞系统调用,那么整个进程会阻塞。而且,因为任意时刻只有一个线程能访问内核,多个线程不能并行运行在多处理器上。(Solaries)
  2. 一对一模型:将每个用户线程映射到一个内核线程。该模型在一个线程执行阻塞系统调用时,能允许另一个线程继续执行,所以它提供比多对一模型更好的并发功能;他也允许多个线程能并行的运行在多处理器系统上.但缺点是每创建一个用户线程就需要创建一个相应的内核线程,开销大,限制了系统所支持的线程数量。(Linux 和 Windows)
  3. 多对多模型:多路复用了许多用户线程到同样数量或更小数量的内核线程上。

4.3 线程库

线程库:为程序员提供创建和管理线程的API.

实现方法:

  1. 在用户空间中提供一个没有内核支持的库。
  2. 执行一个由操作系统直接支持的内核级库。

目前使用三种主要的线程库是:

  1. POSIX Pthread(用户级或内核级)
  2. Win32(内核级)
  3. Java:用户级

4.4 多线程问题

4.4.1 系统调用fork()和exec()

在UNIX中,fork()用两种形式,一种复制所有线程,另一种只复制调用了系统调用fork()的线程。

系统调用exec():如果一个线程调用了系统调用exec(),那么exec()参数所指定的程序会替换整个进程,包括所有线程。

4.4.2 线程取消

线程取消:是在线程完成之前来终止线程的任务。

目标线程取消

  1. 异步取消(asynchronous cancellation):一个线程立即终止 目标线程。
  2. 延迟取消(deferred cancellation):目标线程不断的检查它是否应终止,这允许目标线程有机会以有序方式来终止自己。

4.4.3 信号处理

信号:在UNIX中用来通知进程某个特定事件已发生了。

信号分为同步信号异步信号

信号处理程序:默认处理程序和自定义处理程序。

信号发送:

  1. 发送信号到信号所应用的线程。
  2. 发送信号到进程内的每个线程。
  3. 发送信号到进程内某些固定线程。
  4. 规定一个特定线程以接收进程的所有信号。

4.4.4 线程池

线程池:主要思想是在进程开始时创建一定数量的线程,并放入到池中以等待工作。当服务器收到请求时,他会唤醒池中的一个线程(如果有可以用的线程),并将要处理的请求传递给它。一旦线程完成了服务,它会返回到池中等待以等待工作。如果池中没有可用的线程,那么那么服务器会一直等待直到有空线程为止。

4.4.6 调度程序激活

轻量级进程(LWP):多线程中内核与线程库之间的通信,在许多实现多对多的模型和二级模型系统在用户和内核线程之间设置一种中间数据结构。对于用户线程库,LWP表现为一种应用程序程序可以调度用户线程来运行的虚拟处理器。每个LWP与内核线程相连,该内核线程被操作系统调度到物理处理器上运行。如果内核线程阻塞,LWP也阻塞,相应的与该LWP相连的用户线程也阻塞。

调度激活器(scheduler activation):内核提供一组虚拟处理器(LWP)给应用程序,应用程序可调度用户线程到一个可用的虚拟处理器上。

4.5 操作系统实例

4.5.1 Windows XP 线程

一个线程通常包含:

  • 一个线程ID,以唯一标识线程。
  • 一组寄存器集合,以表示处理器状态。
  • 一个用户栈,以供线程在用户模式下运行;一个内核堆栈,以供线程在内核模式下运行。
  • 一个私有存储区域,为各种运行时库和动态链接库所用。

寄存器集合,栈和私有存储区通常称为上下文

4.5.2 Linux 线程

Linux 提供了具有传统进程复制功能的系统调用 fork(),还提供用系统调用clone()创建线程的功能,Linux并不区分进程和线程。

clone()被调用时,它被传递一组标志,以决定父任务与子任务之间发生多少共享。

第5章 CPU调度

CPU调度是多道程序操作系统的基础。通过在进程之间切换CPU,操作系统可以提高计算机的吞吐率。

5.1 基本概念

多道程序设计:道程序设计技术是在计算机内存中同时存放几道相互独立的程序,使它们在管理程序控制下,相互穿插运行,两个或两个以上程序在计算机系统中同处于开始到结束之间的状态。与之相对应的是单道程序,即在计算机内存中只允许一个的程序运行。

5.1.2 CPU调度程序

每当CPU空闲时,操作系统就必须从就绪队列中选择一个进程来执行。进程选择由短期调度程序或CPU调度程序执行。调度程序从内存中选择一个能够执行的进程,并为之分配CPU.

5.1.3 抢占调度

CPU调度决策发生的四种环境:

  1. 当一个CPU从运行状态切换到等待状态(I/O请求或调用wait)
  2. 当一个进程从运行状态切换到就绪状态(当出现中断)
  3. 当一个进程从等待状态切换到就绪状态(I/O完成)
  4. 当一个进程终止时。
    1和4 没有选择只有调度室非抢占的(采用非抢占的调度,一旦CPU分配一个进程,那么该进程会一直使用CPU直到进程终止或切换到等待状态。

5.1.4 分派程序

分派程序(dispatcher):分派程序是一个模块,用来将CPU的控制交给由短期调度程序选择的进程。其功能包括:

  • 切换上下文
  • 切换到用户模式
  • 掉转到用户程序的合适位置,以重新启动程序。

5.2 调度准则

CPUd调度算法准则:

  • CPU使用率
  • 吞吐量
  • 周转时间
  • 等待时间
  • 响应时间

5.3 调度算法

CPU调度处理是从就绪队列中选择进程并为之分配CPU的问题。

调度算法包括:

  • 先到先服务调度(first-come,first-served(FCFS) Scheduling algorithm):可使用FIFO队列来容易实现。FCFS调度的代码编写简单且容易理解。但其平均等待时间通产较长。
  • 最短作业优先调度(shortest-job-first(SJF) scheduling algorithm):当cpu空闲时,它会赋给具有最短CPU区间的进程。SJF调度算法可证明微微诶最佳的,这是因为对于给定的一组进程,SJF的平均等待时间最小。SJF的难点是无法知道下一个CPU区间的长度。一种方法是近似SJF,预测。SJF可能是抢占的或非抢占的。
  • 优先级调度(priority scheduling algorithm):每个进程都有一个优先级与其关联。优先级调度可以是抢占或非抢占的。但其主要问题是:无穷阻塞(indefinite blocking)或饥饿(starvation)。
  • 轮转法(round-robin,RR):调度算法是专门为分时系统设计的。其类似于FCFS调度,但是增加了抢占以切换进程。定义一个较小的时间单元,称为时间片(time quantum, or time slice).时间片通常为10-100ms.将就绪队列作为循环队列。CPU调度程序循环就绪队列,为每个进程分配不超过一个时间片的CPU.RR算法的性能很大程度上依赖于时间片的大小。在极端情况下,如果时间片非常大,那么RR算法与FCFS算法一样。如果时间片很小,那么RR算法称为处理器共享,在理论上讲,n个进程对于用户都有它自己的处理器,速度为真正处理器速度的1/n。
  • 多级队列调度(multilevel queue scheduling algorithm):将就绪队列分成多个独立队列。根据进程的属性,如内存大小,进程优先级,进程类型,一个进程被永久的分配到一个队列。每个队列有自己的调度算法。队列和队列之间必须有调度,通常采用固定优先级抢占调度。
  • 多级反馈队列调度算法(mutilevel feedback queue scheduling algorithm):与多级队列调度相反,其允许进程在队列之间移动。主要思想是根据CPU区间的特点以区分进程。如果进程使用过多的CPU时间,那么它会被转移到更低优先级队列。此外,在较低优先级队列中等待时间过长的进会被转移到更高优先级队列。

5.4 多处理器调度

5.4.1 多处理器调度的方法

非对称多处理器(asymmetric multiprocessing):在一个多处理器中,CPU调度的方法是让一个处理器(主服务器)处理所有的调度决定,I/O处理以及其他活动,其他的处理器值执行用户代码。

对称多处理器(symmetric multiprocessing,SMP):即每个处理器自我调度。所有进程可能处于一个共同的就绪队列中,或每个处理器都有它自己的私有就绪进程队列。无论如何,调度通过每个处理器检查共同就绪队列并选择一个进程来执行。

5.4.2 处理器亲和性

处理器亲和性:由于使缓存无效或重构代价高,对大多数SMP系统试图避免将进程从一个处理器移至另一个处理器,而是努力使一个进程子啊同一个处理器上运行,被称为处理器亲和性。

5.4.3 负责平和

负载平衡(load balanceing):设法将工作负载平均的分配到SMP系统中的所有处理器。

负载平和通常有两种方法:

  • push migration:一个特定的任务周期性的检查每个处理器上的负载,如果发现不平衡,即通过将进程从超载处理器移到(或推送到)空闲或不太忙的处理器,从而平均低分配负载。当空闲处理器从一个忙的处理器上推送(pull)一个等待任务时,发生
  • pull migration:当空闲处理器从一个忙的处理器上推送(pull)一个等待任务时,发生pull miggration。

5.4.4 对称多线程

提供多个物理处理器,SMP系统允许同时运行几个线程。另一种方法是提供多个逻辑(而不是物理)处理器来实现。这种方法被称为对称多线程(SMT),在Intel 处理器上,被称为超线程(hyperthreading)技术。

SMT的思想是在同一个物理处理器上生成多个逻辑处理器,下个操作系统呈现一个多逻辑处理器的试图,即使系统仅有单处理器。

5.5 线程调度

用户线程和内核贤线程的区别之一就是他们说是如何被调度的。

在执行多对一和多对多的模型时,线程库调度用户级线程到一个有效LWP上运行,被称为进程竞争范围(process-contention scope,PCS),因为CPU竞争发生在属于相同进程的线程之间。

为了决定调度哪个内核线程到CPU,内核采用系统竞争范围(system-contention scope,SCS).采用SCS调度方法,竞争CPU发生在系统的所有线程中。

5.6 操作系统实例

Solaris :采用基于优先级的线程调度。

Windos XP:基于优先级的,抢占调度算法来调度线程。

Linux调度:抢占的,基于优先级的算法,具有两个独立的优先级范围:从0~99的real-time范围和从100~140的nice范围。其映射到全局
优先级,其中数值越低表明优先级越高。Linux给较高的优先级分配较长的时间片,给较低的优先级分配较段的时间片。

第6章 进程同步

多个进程并发访问和操作同一数据且执行结果与访问发生的特定顺序有关,称为竞争条件(race condition)。为了避免竞争条件,需要确保一段时间内只有一个进程能操作变量,其必须进行一定形式的同步。

6.2 临界区

临界区(critial section)特点:

  • 互斥(mutual exclusion):如果进程P在其临界区执行,其他进程都不能在其临界区执行。
  • 前进(progress):如果没有进程在其临界区内执行且有进程序进入临界区,那么只有那些不再剩余区内执行的进程可参加选择,以确定谁能在下一个进入临界区,且这种选择不能无限推迟。
  • 有限等待(bounded waiting):从一个进程做出进入临界区的请求知道请求被允许为止,其他进程允许进入临界区的次数有上限。

两种处理操作系统内临界区问题的方法:

  • 抢占内核(preemptive kernel):抢占内核允许处于内核模式的进程被抢占。
  • 非抢占内核(nonpreemptive kernel):不允许处于内核模式的进程被抢占。

6.4 硬件同步

:在进入临界区之前得到锁,而在其退出临界区是释放锁。

许多现代操作系统提供了特殊硬件指令以允许能原子地(不可中断地)检查和修改子的内容或交换两个字的内容。

6.5 信号量

信号量(semaphore):一种同步工具,信号量S是个整数变量,除了初始化外,他只能通过两个标准原子操作:wait()和signal()来访问。

6.8 同步实例

  1. Solaris:为了控制访问临界区,Solaris提供了适应互斥,条件变量,信号量、读写锁和十字转门。
  2. Linux :抢占内核,,提供自旋锁和信号量以进行内核加锁。

第7章 死锁

死锁(deadlock):在多道程序环境下,多个进程可能竞争一定数量的资源。某个进程申请资源,如果这时资源不可用,那么该进程进入等待状态。如果所申请的资源被其他等待进程占有,那么该等待进程有可能再也无法其状态。

在正常模式下,进程只能按如下顺序使用资源:

  1. 申请
  2. 使用
  3. 释放

7.2 死锁特征

当出现死锁时,进程永远不能完成,并且系统资源被阻碍使用,阻止了其他作业开始执行。

7.2.1 必要条件

  1. 互斥
  2. 占有并等待
  3. 非抢占
  4. 循环等待

7.2.2 资源分配图

死锁问题可用称为系统资源分配图的有向图进行更为精确的描述。

若分配图没有环,那么系统就没有进程死锁。如果分配图有环,那么可能存在死锁。

7.3 死锁处理方法

  1. 可使用协议以预防或避免死锁;
  2. 可允许系统进入死锁状态,然后检测它,并加以恢复;
  3. 可护士这个问题,认为死锁不可能在系统内发生;

死锁预防(deadlock prevention):是一组方法,以确保至少一个必要条件不成立;

死锁避免(deadlock avoidance):要求操作系统事先得到有关进程申请资源和使用资源的额外信息。

7.7 死锁恢复

  1. 进程终止:终止所有死锁进程;一次只终止一个进程知道取消死锁循环为止;
  2. 资源抢占:(1)选择一个牺牲品;(2) 回滚

以上是关于第二部分:进程管理的主要内容,如果未能解决你的问题,请参考以下文章

Android Detail:进程篇-进程内存分配与优先级

核心数据删除问题:第二部分

『学了就忘』Linux系统管理 — 3.进程的查看(top命令)

python后端面试第二部分:网络编程--长期维护

php多进程实例

Linux基础