进程与线程

来源:互联网 发布:各个协议的端口号列表 编辑:程序博客网 时间:2024/06/15 08:41

2.1 进程与线程

  操作系统越复杂,期望它能够为用户做的事情越多。虽然它主要关注用户程序的执行,但是也需要处理内核自身之外的各种系统任务。系统由进程集合组成:操作系统进程执行系统代码,用户进程执行用户代码。通过CPU在进程间多路复用,所有这些进程潜在地能够并行执行。通过在进程间转换CPU,操作系统可以使计算机获得更好的性能。

2.1.1 进程概念及特征

  1.进程的概念
  进程(Process)这个术语最早是1960 年在MIT 的MULTICS 和IBM 公司的TSS/360系统中提出来的,直到目前对进程的定义和名称还尚不统一,不同的系统采用不同的术语名称,如MIT称进程(Process),IBM公司称任务(Task),Univac 公司称活动(Active)。因此,进程的定义有很多种。
  这里较能反映进程实质的定义如下。
  进程是程序的一次执行。
  进程是可以和别的计算机并发执行的计算。
  进程可定义为一个数据结构,以及能在其上进行操作的一个程序。
  进程是一个程序及其数据在处理机上顺序执行时所发生的活动。
  进程是程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位。
  需要注意的是,虽然两个进程与同一个程序相关,但是它们被当作两个独立的执行序列,虽然文本段相同,但是数据段不同。总之,进程的概念可以这样理解,进程是一个可并发执行的具有独立功能的程序关于某个数据集合的一次执行过程,也是操作系统进行资源分配和保护的基本单位。
  2.进程的特征
  进程并发执行时,与顺序程序的特征完全不同,它破坏了顺序程序的封闭性和可再现性。表现在它具有以下特征。
  动态性:进程是进程实体的执行过程。因此,动态性是进程最基本的特征。进程具有一定的生命周期,即进程由创建而产生,由调度而执行,因得不到资源而暂停执行,以及由撤销而消亡。
  并发性:多进程同时存在于内存中,在一段时间内同时运行。
  独立性:未建立进程的程序,都不能作为一个独立的单元运行。
  异步性:进程按各自独立的、不可预知的速度向前推进,导致程序具有不可再现性。因此,在操作系统中,必须采取某种措施来保证各程序之间能协调运行。
  结构特征:由程序(段)、数据(段)和进程控制块组成。
  3.进程的组成及与程序之间的联系与区别
  从进程的定义和结构来看,进程由程序、数据和进程控制块三部分组成。程序和数据是进程完成指定功能所必需的运行实体,而进程控制块是进程存在的唯一标识,是系统对进程进行管理和控制的实体。
  进程是程序的一次执行过程,没有程序就没有进程。程序是完成某个特定功能的一系列程序语句的集合,只要不被破坏,它就永远存在。程序是一个静态的概念,而进程是一个动态的概念,它由创建而产生,完成任务后因撤销而消亡;进程是系统进行资源分配和调度的独立单位,而程序不是。
  4.引入进程的利弊
  引入进程是基于多道程序和分时系统的需要,因为只有为每道程序建立了进程,它们才能并发执行。通过进程的并发执行,来改善系统的资源利用率和提高系统的吞吐量。因此目前大多数系统几乎都引入了进程,但系统也为此付出了下述开销:
  空间开销:系统必须为每个进程建立进程控制块(PCB),它通常要占用几十到几百个内存单元;此外,为了协调各进程的并发执行,系统还必须设置相应的进程管理机构,这也必然占用可观的内存空间;
  时间开销:为了协调各进程的运行,也必须付出时间开销;例如,在进行进程切换时,系统必须保证存在运行进程的现场,为即将运行的线程设置新现场,这都需要花费CPU时间。

 

2.1.2 进程的状态与转换

  在操作系统中,进程在不同的阶段有不同的状态,而且各种状态之间是可以转换的。下面将介绍进程的各种状态及状态的转换。
  1.进程的基本状态
  一个进程从创建而产生至撤销而消亡的整个生命期间,有时占有处理器执行,有时虽可运行但分不到处理器、有时虽有空闲处理器但因等待某个事件的发生而无法执行,这一切都说明进程和程序不相同,它是活动的且有状态变化的,这可以用一组状态加以刻画。为了便于管理进程,按进程在执行过程中的不同情况,可将进程分为以下几种基本状态。
  执行状态(Running):进程占用处理机正在执行其程序。单处理机系统中只能有一个进程处于执行状态,多处理机系统中可能有多个进程处于执行状态。
  阻塞状态(Blocked):也叫等待或睡眠状态,是进程由于等待某种事件的发生而处于暂停执行的状态。如进程因等待I/O的完成、等待缓冲空间等。
  就绪状态(Ready):进程已分配到除处理机以外的所有必要资源,具备了执行的条件,可能会有多个进程处于就绪状态,排成就绪队列。
  2.新状态和终止状态
  新状态:进程刚刚建立,还没有送入就绪队列的状态。
  终止状态:一个进程已正常结束或非正常结束,操作系统已将它从就绪队列中移出,尚未将它撤销时的状态。
  3.进程状态的转换
  进程在执行期间,可以多次处于就绪状态和执行状态,也可以多次处于阻塞状态,但处于新状态只有一次。图2-1显示了各种状态之间的转换流程,状态之间的转换大体包含如下几种。

  新状态到就绪状态:当就绪队列允许接纳新进程时,系统便把处于新状态进程移入就绪队列。
  就绪状态到执行状态:进程调度程序为处于就绪状态的进程分配处理机后,该进程进入执行状态。
  执行状态到阻塞状态:正在执行的进程因需要等待某事件而无法执行,让出处理机。
  阻塞状态到就绪状态:进程所等待的事件发生了,进程就从阻塞状态进入就绪状态。
  执行状态到就绪状态:正在执行的进程因时间片用完而被暂停执行;或者在可抢占调度方式中,一个优先权高的进程到来后,正在执行的优先权低的进程被强制撤下处理机,转换为就绪状态。
  执行状态到终止状态:一个进程已完成或发生某种特殊事件,进程将变为终止状态。

 

2.1.3 进程控制

  进程控制的内容主要包括进程控制机构、进程的创建、进程的终止等内容,下面我们分别介绍这些内容。
  1.进程控制机构
  操作系统作为资源管理和分配程序,其本质任务是自动控制程序的执行,并满足进程执行过程中提出的资源使用要求。因此,操作系统的核心控制结构是进程结构,资源管理的数据结构将围绕进程结构展开。
  操作系统使用系统原语控制进程状态改变,原语被认为是机器语言的延伸,是完成特定任务的一段基本程序,它具有原子操作性。原子操作是不可分的操作,要么全做,要么全不做,它是通过中断屏蔽来实现的。原语对用户是透明的,一般不允许直接使用,但是允许程序员作为一种特殊的系统调用来使用。
  操作系统的控制表分为四类:进程控制表,存储控制表,I/O 控制表和文件控制表。
  进程控制表用来管理进程及其相关信息。
  存储控制表用来管理一级(主)存储器和二级(辅)存储器,主要内容包括:主存储器的分配信息,二级存储器的分配信息,存储保护和分区共享信息,虚拟存储器管理信息。
  I/O控制表用来管理计算机系统的I/O 设备和通道,主要内容包括:I/O 设备和通道是否可用,I/O设备和通道的分配信息,I/O 操作的状态和进展,I/O 操作传输数据所在的主存区。
  文件控制表用来管理文件,主要内容包括:被打开文件的信息,文件在主存储器和二级存储器中的位置信息,被打开文件的状态和其他属性信息。
  2.主要进程原语
  (1)创建原语(Create)
  进程创建的方式有两种:一是由系统程序模块统一创建,二是由父进程创建。它们都需要调用创建原语来实现。创建原语的主要工作是,首先扫描系统的PCB表,查询有无空的PCB表项,如有,则申请一个,并对其进程初始化,初始化的项目有进程标识符(PID)、进程状态和执行程序的起始地址;如果申请不成功,则创建失败。
  进程的创建过程描述如下。
  在主进程表中增加一项,并从PCB 池中申请一个空白PCB。
  为新进程的进程映像分配地址空间。对于进程创建操作还需要传递环境变量,构造共享地址空间。
  为新进程分配资源,除内存空间外,还有其他各种资源。
  查找辅助存储器,找到进程正文段并装入到进程地址空间的正文区。
  初始化进程控制块(如状态、PSW、栈等),为新进程分配一个唯一的进程标识符。
  把进程加入某一就绪进程队列(这时子进程就绪),或直接将进程投入运行(这时父进程就绪)。
  通知操作系统的某些模块,如记账程序、性能监控程序。
  (2)撤销原语(Kill)
  当进程正常执行完毕后,或者由于某种错误非正常终止时,都需要调用撤销原语来释放该进程所占用的各种资源和PCB结构本身,以利于有效地使用资源。撤销原语的主要工作是,首先检查PCB链表,寻找所要撤销的进程是否存在。如果找到了相应的表项,撤销原语就释放该进程占用的资源并回收对应的PCB结构;如果被撤销的进程还有子进程,则撤销原语必须先撤销子进程的  PCB并释放其所占用的资源。
  进程撤销的具体步骤如下。
  根据撤销进程标识号,从相应队列中找到它的PCB。
  将该进程拥有的资源归还给父进程或操作系统。
  若该进程拥有子进程,应先撤销它的所有的子孙进程,以防它们脱离控制。
  撤销进程出队,将它的PCB 归还到PCB 池。
  (3)阻塞原语(Block)
  当进程等待某些事件(如读写磁盘、接受其他进程的数据)的产生时,通过执行阻塞原语来阻塞自己。阻塞原语在执行时,必须先中断处理机并同时保存该进程的CPU现场。然后将阻塞进程插入到等待队列中,再转由调度程序从就绪队列中选择一个进程投入运行。进程阻塞的步骤如下。
  停止进程执行,保存现场信息到PCB。
  修改进程控制块的有关内容,如进程状态由运行改为等待等。
  把修改状态后的进程控制块加入相应等待进程队列。
  接着便应转入进程调度程序去调度其他进程运行。
  (4)唤醒原语(Wakeup)
  又称为恢复原语,当进程等待的条件或事件产生后,等待该事件的所有进程都被唤醒。唤醒进程的方法有两种:一种是系统进程唤醒;另一种是由事件发生进程唤醒。它们都需要调用唤醒原语来唤醒另一进程。唤醒原语首先将被唤醒进程从相应的等待队列取下,并将其状态设置为就绪态后,送入就绪队列。此时,唤醒原语既可以从调用程序处直接返回,也可以转向进程调度程序,让调度程序选择一个合适的进程去执行。需要注意的是,一个进程由执行状态转变为阻塞状态,是这个进程自己调用阻塞原语去完成的;而进程由阻塞状态到就绪状态,是另一个发现者进程调用唤醒原语实现的,一般这个发现者进程与被唤醒进程是合作的并发进程。进程唤醒的步骤如下。
  从相应的等待进程队列中取出进程控制块。
  修改进程控制块的有关信息,如进程状态改为就绪。
  把修改后的进程控制块加入有关就绪进程队列。
  (5)挂起原语(Suspend)
  当用户或创建者需要了解进程的活动情况或干预进程活动时,可以把某进程置于挂起就绪状态或挂起阻塞状态,这时,要调用挂起原语,挂起方式如下。
  发命令进程自身挂起。
  挂起具有制定标识符的进程。
  将某进程及其全部或部分子进程挂起。
  (6)激活原语(Active)
  激活原语使处于静止状态的进程变为活动状态,即供用户或创建者重新激活已挂起的进程,激活方式有多种,如激活一个指定标识符的进程,或激活某进程及其所有子进程等。当激活后的进程处于活动就绪状态时,将引起重新调度。
  进程在系统中能够并行执行,并且它们必须要动态地创建和删除。因此,操作系统必须提供进程创建和终止的机制(或方法)。
  3.进程的创建
  进程在运行期间,通过创建进程系统调用可以创建多个新进程。创建进程的进程被称为父进程,而新进程被称为子进程。每个新进程都可以创建另外的进程,从而形成一个进程树。
  每一个进程都有生命期,即从创建到消亡的时间周期。当操作系统为一个程序构造一个进程控制块并分配地址空间之后,就创建了一个进程。进程的创建来源于以下四个事件。
  提交一个批处理作业。
  在终端上一个交互式作业登录。
  操作系统创建一个服务进程。
  存在的进程创建新的进程。
  4.进程的终止
  进程执行完最后一条语句后就终止执行,并调用exit系统调用来使操作系统删除它。在此,该进程可能要把数据(输出)返回给它的父进程(通过wait系统调用)。操作系统回收该进程的所有资源——包括物理和虚拟内存、打开文件和I/O 缓冲器。
  进程也可能在其他的情况下终止运行。一个进程可以利用系统调用(例如:abort)终止其他的进程。通常,只有进程的父进程可以调用这样的系统调用来终止它。否则,用户可以任意地取消其他用户的作业。所以父进程需要知道其子进程的标识符。如此,当一个进程创建一个新进程时,新创建的进程的标识符要传给其父进程。
  父进程可能会出于某种原因而结束它的一个子进程,例如:
  子进程需要更多的资源。这需要父进程能够检查其子进程的状态;
  分配给子进程的任务已经不再需要;
  父进程退出,而且操作系统禁止子进程在父进程终止后继续执行。在这样的系统中,如果一个进程(正常或非正常)终止,那么它的所有子进程也必须终止。通常这种级联式的进程终止是操作系统发起的。

2.1.4 进程组织

  进程组织是指进程的组织方式,下面从进程实体和进程控制块两个方面来了解进程的组织结构。
  1.进程实体
  在操作系统中,一个进程是通过其物理实体被感知的,进程的物理实体又称为进程的静态描述。进程的静态描述通常由三部分组成:程序、数据集合、进程控制块(PCB)。
  程序:描述进程所要完成的功能。
  数据集合:程序运行所需要的数据部分和工作区。
  进程控制块:包含了进程的描述信息、控制信息和资源信息,是进程动态特性的集中反映。
  程序是产生进程的基础,通过进程产生进程。如果一个程序能为多个进程同时共享执行,那么这部分就以纯码,也就是再入码形式编制,它是进程执行时不可修改的部分。数据集合通常为一个进程独占,为进程的可修改部分。程序和数据集合是进程存在的物质基础,是进程的实体。进程控制块是进程存在的标志,进程与进程控制块是一对一的关系,进程控制块记录进程的控制信息和描述信息,操作系统利用进程控制块对并发执行的进程进行控制和管理,进程控制块是操作系统中最重要的记录行数据结构。
  2.进程控制块(PCB)
  PCB是保存进程的状态和控制进程转换的标识,也是进程存在的唯一标识。创建进程则产生PCB,撤销进程系统就要回收PCB。图2-2给出了一个PCB的例子,PCB主要包括描述信息、管理信息、资源清单、现场保护区和其他功能。操作系统通过PCB表(或队列)来管理与控制进程。PCB表项的个数是确定的,所以也就限制了系统中进程的个数不能超过某个值。

  (1)进程描述信息
  进程标识符:标识各个进程,每个进程都有一个并且是唯一的标识名或标识号。
  用户标识符:每个进程属于某个用户,用户标识符主要为共享和保护服务。
  (2)进程控制信息
  进程当前状态:作为调度程序分配处理机的依据。当进程处于阻塞状态时,要在PCB中说明阻塞原因。
  进程优先级:表示进程使用CPU时优先级别的一个整数。优先级高的进程可优先获得处理机。
  代码执行入口地址。
  程序的外存地址:进程执行程序的地址。
  各种计时信息:给出进程执行时间、页面调度情况。
  通信信息:用来说明该进程与其他进程的信息交换情况,如进程同步、阻塞原因等。
  (3)资源管理信息
  用于说明有关虚拟地址空间的现状、打开文件列表和使用的输入/输出设备信息。
  (4)CPU现场保护结构
  CPU现场保护结构保存寄存器值,如通用寄存器、程序计数器PC、状态PSW、地址包括栈指针的值等。
  在系统中PCB数目较多,应该采用合适的方式,将它们组织起来,进行有效的管理。目前常用的组织方式有链接方式和索引方式两种。
  链接方式
  把具有相同状态的PCB,用其中的链接字,链接成一个队列。这样可形成就绪队列、阻塞队列等。对其中的就绪队列按进程的优先权排列,把优先权高的PCB排在前面。另外,也可根据阻塞原因把阻塞状态进程的PCB排成等待I/O操作完成、等待分配内存等队列。
  索引方式
  根据所有进程的状态,建立几张索引表,如就绪索引表、阻塞索引表等。并把各索引表在内存的首地址记录在内存中的一些专用单元。在每个索引表的表目中,记录具有相应状态的某个PCB在PCB表中的地址。

 

2.1.5 进程通信

  进程间的信息交换称为进程通信,进程之间的互斥与同步就是两种进程通信方式。由于进程互斥与同步交换的信息量较少,每次通信传递的信息量固定且效率较低,因此称这两种通信方式为低级通信方式;相应地,也可将P、V操作称为两条低级通信原语。所谓高级通信方式是指进程之间以较高的效率传送大量数据的通信方式。
  高级通信方式可分为三大类:共享存储器系统、消息传递系统以及管道通信系统。
  1.共享存储器系统
  在这种方式中,相互通信的进程共享某些数据结构或共享存储区,具体可分为以下两种方式:
  一种是高级通信方式的共享存储区:是指进程之间通过对共享存储区的读/写,来交换数据;
  另一种方式是利用共享的数据结构来进行进程通信,进程之间通过某种类型的数据结构来交换信息,如生产者-消费者问题,便是利用有界缓冲区这种数据结构来进行通信的。但这种方式对共享数据结构的设置及对进程间的同步,都必须由程序员来处理,且只能进行少量的数据交换,因此,属于低级通信方式。
  2.消息传递系统
  在消息传递系统中,消息系统的功能是允许进程与其他的进程进行通信而不必借助共享数据,进程间的数据交换以格式化的消息(报文)为单位。根据实现方式的不同,它又可分为直接通信和间接通信两类。
  在直接通信方式中,源进程可直接将消息发送给目标进程,此类操作系统通常提供send(receiver, message)和receive(sender,message)两条通信命令(原语)供用户使用。
  在间接通信方式中,进程间需要通过某种中间实体(即信箱)来进行通信。发送进程将消息投入信箱,而接受进程则从信箱中取得消息。因此,它不仅能实现实时通信,还能实现非实时通信。此时,操作系统应提供若干条原语,分别用于信箱的创建、撤销和消息的发送、接收等。
  如果进程P 和Q 要进行通信,那么它们必须能够互相发送和接收消息;两者之间必须要建立一条通信链路。有多种方法可以实现这条链路。在这里,我们并不关心链路的物理实现,而是要考虑它的逻辑实现。有如下几种用于逻辑实现和send/receive 操作的方法:
  直接或间接通信;
  对称或不对称通信;
  自动或手动缓冲;
  发送复制或引用;
  定长消息或变长消息。
  (1)直接通信
  直接通信中,需要通信的每个进程都必须直接指明通信的接收方或发送方。在这种方式下,发送和接收原语定义如下:
  send(P,message)——发送一个消息给进程P;
  receive(Q,message)——从进程Q中接收一个消息。
  这种通信链路具有如下特点:
  每对需要通信的进程之间自动地建立一条链路。进程只需要知道彼此的标识符;
  一个连接就只连接到这两个进程;
  每对进程间只能建立一条链路。
  这种机制在寻址上对称。发送者和接收者进程都必须要指明通信的另一方。这种机制的一个变种在寻址上采用了不对称的方式。只需发送者指明接收者;而接收者不需要指明发送者。在这种方式下,发送和接收原语定义如下:
  send(P,message)——发送一个消息给进程P;
  receive(id,message)——从任意进程中接收一个消息;变量id 被联系到与之通信的进程的名称。
  对称和不对称机制的缺点在于它限制了进程定义的模块化程度。更改一个进程的名称可能必须要检查其他所有进程的定义。必须要发现所有对原名称的引用,以便于更换为新名称。从独立编译角度来看,这种情形可不是希望看到的。
  (2)间接通信
  间接通信中,消息的发送和接收通过信箱(或端口)进行。可以抽象地把信箱看成一个对象,进程可以把消息放置其中也能从中取走。每个信箱都有一个唯一的标识符。在这种方式下,进程可以通过不同的信箱与其他进程通信。两个进程只有共享一个信箱才可以进行通信。发送和接收原语定义如下:
  send(A,message)——向信箱A中发送一个消息;
  receive(A,message)——从信箱A中接收一个消息。
  这种通信链路具有如下特点:
  只有在两个进程间有一个共享信箱的情况下才能在两者之间建立一个链接;
  一条链路可以连接两个或更多进程;
  在每对通信进程之间可以同时存在多个不同的链路,每条链路对应一个信箱。
  假设进程P1、P2和P3 共享信箱A,而且P2 和P3 正从A 中接收。那么谁将接收到P1 发送的消息呢?答案与我们选择的方案有关:
  允许一条链路最多连接两个进程;
  同时最多允许一个进程执行接收操作;
  允许系统任意选择进程来接收消息[就是说,P2 或者P3(但不能都是)将接收消息]。系统可能会确定接收者。
  一个信箱可能为一个进程或操作系统所有。如果信箱的所有者是一个进程(也就是说,此信箱占据了该进程的部分地址空间),那么就要区分所有者(唯一可以从这个信箱中接收消息)和用户(只能够向这个信箱中发送消息)。因为每个信箱有一个唯一的所有者,所以谁可以从此信箱中接收消息就很明确了。当一个拥有一个信箱的进程终止时,信箱也要消失。随后,向这个信箱发送消息的进程都会被告知该信箱已经不存在了。
  另外,操作系统拥有的一个信箱是独立的且不会依附于任何进程。那么操作系统必须要提供一种机制以允许一个进程做如下的工作:
  创建一个新信箱;
  通过这个信箱发送和接收消息;
  删除一个信箱。
  创建了一个新信箱的进程默认为该信箱的所有者。最初,所有者是唯一能够从此信箱中接收消息的进程。然而,可以通过系统调用将(信箱的)所有权和接收权交给其他进程。当然,这会造成每个信箱有多个接收者的情况。
  3.管道通信
  所谓管道通信,是指连接两个进程的一个打开的共享文件。发送进程以字符流的形式将大量的信息写入管道,接收进程则在需要时从管道中读出数据。为了协调双方的通信,管道通信机制必须对发送进程和接收进程在利用管道进行通信时实施同步和互斥,并且只有在确定双方存在时才能进行通信。

 

2.1.6 线程概念与多线程模型

  本节将重点介绍线程的概念、作用、实现方式及线程与进程的区别,另外简单介绍多线程模型。
  1.线程的引入
  在传统操作系统的单线程进程中,进程和线程概念可以不加区别。图2-3给出了单线程进程的内存布局和结构,它由进程控制块和用户地址空间,以及管理进程执行的调用/返回行为的系统堆栈或用户堆栈构成。一个进程的结构可以划分为两个部分:对资源的管理和实际的指令执行序列。显然,采用并发多进程程序设计时,并发进程之间的切换和通信均要借助于操作系统的进程管理和进程通信机制,因而实现代价较大,而较大的进程切换和进程通信代价,又进一步影响了并发的粒度。

  设想是否可以把进程的管理和执行任务相分离,如图2-4所示,让进程是操作系统中进行保护和资源分配的单位,允许一个进程中包含多个可并发执行的控制流,这些控制流切换时不必通过进程调度,通信时可以直接借助于共享内存区,每个控制流称为一个线程,这就是并发多线程程序设计。

  多线程进程的内存布局如图2-5所示,在多线程环境中,仍然有与进程相关的内容是PCB 和用户地址空间,而每个线程除了有独立堆栈,以及包含现场信息和其他状态信息外,也要设置线程控制块TCB(Thread Control Block)。线程间的关系较为密切,一个进程中的所有线程共享其所属进程拥有的资源,它们驻留在相同的地址空间,可以存取相同的数据。例如,当一个线程改变了主存中的一个数据项时,如果这时其他线程也存取这个数据项的话,它便能看到相同的结果。

  在操作系统中引入进程的目的是为了使多个程序并发执行,以改善资源利用率及提高系统的吞吐量,那么,在操作系统中再引入线程,则是为了减少程序并发执行时所付出的时空开销,使操作系统具有更好的并发性能。
  线程是进程中的一个实体,是被系统独立调度和分派的基本单位。线程自己基本上不拥有系统资源,只拥有在运行中必不可少的资源,如线程状态、寄存器上下文和栈。它同样有就绪、阻塞和执行三种基本状态。它可与同属一个进程的其他线程共享进程所拥有的全部资源。一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中也呈现出间断性。
  2.线程实现方式
  内核线程:它依赖于操作系统内核,由内核的内部需求进行创建和撤销,用来执行一个指定的函数。一个线程发起系统调用而阻塞,不会影响其他线程。它通过时间片分配给线程,所以,多线程的进程获得更多CPU时间。
  用户线程:不依赖于操作系统内核,应用进程利用线程库提供创建、同步、调度和管理线程的函数来控制用户线程。调度在应用软件内部进行,通常采用非抢先式和更简单的规则,也无须用户态和核心态切换,所以速度特别快。
  轻权进程:它是操作系统内核支持的用户线程。一个进程可有一个或多个轻权进程,每个轻权进程由一个单独的内核线程来支持。
  3.进程机制与线程机制的比较
  在引入线程的操作系统中,通常一个进程有若干个线程,至少也需要有一个线程。下面从5个方面来比较线程和进程。
  调度
  在传统的操作系统中,进程是拥有资源的基本单位和独立调度、分派的基本单位。而在引入线程的操作系统中,则把线程作为调度和分派的基本单位,把进程作为资源拥有的基本单位。
  并发性
  在引入线程的操作系统中,不仅进程之间可以并发执行,而且在一个进程的多个线程之间,也可并发执行。因而使操作系统具有更好的并发性,从而能够有效地使用多个资源和提高系统吞吐量。
  拥有资源
  一般来说,线程除了拥有一点必不可少的资源外,它自己不拥有系统资源,但它可以访问其隶属进程的资源。也就是说,一个进程所拥有的资源可供它所有的线程共享。
  系统开销
  在有的系统中,线程的切换、同步和通信都无须操作系统内核的干预。
  通信方面
  进程间通信需要进程同步和互斥手段的辅助,以保证数据一致性,而线程间可以通过直接读/写进程数据段(如全局变量)来进行通信。
  4.多线程模型
  线程是操作系统进程中能够独立执行的实体(控制流),是处理器调度和分派的基本单位。线程是进程的组成部分,每个进程内允许包含多个并发执行的实体(控制流),这就是多线程。
  许多系统都提供用户和内核线程支持,从而有不同的多线程模型。下面我们看一下三种常见的线程模型。
  多对一模型
  多对一模型(如图2-6所示)将多个用户线程映射到一个内核线程。线程管理是在用户空间进行的,因而效率比较高;但是,如果一个线程执行了阻塞系统调用,那么整个进程就会阻塞。而且,因为任一时刻只有一个线程能访问内核,所以多个线程不能并行运行在多处理器上。
  一对一模型
  一对一模型(如图2-7所示)将每个用户线程映射到一个内核线程。该模型在一个线程执行阻塞系统调用时,能允许另一个线程继续执行,所以,它提供了比多对一模型更好的并发功能;它也允许多个线程能在多处理系统上并行地运行。这种模型的唯一缺点是,创建一个用户线程需要一个相应的内核线程。由于创建内核线程的开销会影响应用程序的性能,所以,这种模型的实现大多数限制了系统所支持的线程数量。
  多对多模型
  多对多模型(如图2-8所示)是多路复用许多用户线程到同样数量或更小数量的内核线程上。内核线程的数量可能与特定应用程序或特定机器有关(位于多处理器上的应用程序可比单处理器上的应用程序分配更多数量的内核线程)。虽然多对一模型允许开发人员随意创建任意多的用户线程,但是由于内核只能一次调度一个线程,所以并不能增加并发性。一对一模型提供了更大的并发性,但是开发人员必须小心,不要在应用程序内创建太多的线程。而多对多模型没有这两方面的缺点,开发人员可创建任意多的必要用户线程,并且相应内核线程能在多处理器系统上并行执行。并且,当一个线程执行阻塞系统调用时,内核能调度另一个线程来执行。
  5.并发多线程程序设计的优点
  在一个进程中包含多个并行执行的控制流,而不是把多个可并发执行的控制流一一分散在多个进程中,这是并发多线程程序设计与并发多进程程序设计的不同之处。并发多线程程序设计的主要优点是使系统性能获得很大提高,具体表现在以下几个方面。

       

  快速线程切换。进程具有独立的虚地址空间,以进程为单位进行任务调度,系统必须交换地址空间,切换时间长,而在同一进程中的多线程共享同一地址空间,因而,能使线程快速切换。
  减少(系统)管理开销。对多个进程的管理(创建、调度、终止等)系统开销大,如在响应客户请求建立一个新的服务进程的服务器应用中,创建的开销比较显著。面对创建、终止线程,虽然也有系统开销,但要比进程小得多。
  (线程)通信易于实现。为了实现协作,进程或线程间需要交换数据。对于自动共享同一地址空间的各个线程来说,所有全局数据均可自由访问,不需什么特殊设施就能实现数据共享。而进程通信则相当复杂,必须借助诸如通信机制、消息缓冲、管道机制等设施,并且还要调用内核功能才能实现,同时线程通信的效率也很高。
  并发程度提高。许多多任务操作系统限制用户能拥有的最多进程数目,如早期的UNIX 一般为50个,这对许多并发应用来说是不够的。而对多线程技术来说,一般可达几千个,基本上不存在线程数目的限制。
  节省内存空间。多线程合用进程地址空间,而不同进程独占地址空间,使用不经济。
  由于队列管理和处理器调度是以线程为单位的,因此,多数涉及执行的状态信息被维护在线程数据结构中。然而,有一些影响到一个进程中所有线程的活动,操作系统必须在进程级进行管理。挂起意味着将主存中的地址空间对换到磁盘上,因为,在一个进程中的所有线程共享同一地址空间,此时,所有线程也必须进入挂起状态。相似地,终止一个进程时,所有线程应被终止。

2.1.7 线程管理与线程池

  多线程技术是利用线程池来提供一整套有关线程的原语集来支持多线程运行的,有的操作系统直接支持多线程,而有的操作系统不支持多线程。因而,线程池可以分成两种:用户空间中运行的线程池和内核中运行的线程池。一般来说,线程池至少应提供以下功能的原语调用:孵化、封锁、活化、结束、通信、同步、互斥等,以及切换(保护和恢复线程上下文)的代码,调度(对线程的调度算法及实施处理器调度)的代码。同时应提供一组与线程有关的应用程序编程接口API,支持应用程序创建、调度、撤销和管理线程的运行。
  基本的线程控制原语有如下4种。
  孵化(spawn):又称创建线程。当一个新进程被生成后,该进程的一个线程也就被创建。此后,该进程中的一个线程可以孵化同一进程中的其他线程,并为新线程提供指令计数器和参数。一个新线程还将被分配寄存器上下文和堆栈空间,并将其加入就绪队列。
  封锁(block):又称线程阻塞或等待。当一个线程等待一个事件时,将变成阻塞态,在保护它的用户寄存器、程序计数器和堆栈指针等现场后,处理器就可以转向执行其他就绪线程。
  活化(unblock):又称恢复线程。当被阻塞线程等待的事件发生时,线程变成就绪态或相应状态。
  结束(finish):又称撤销线程。当一个线程正常完成时,便回收它占有的寄存器和堆栈等资源,撤销线程TCB。当一个线程运行出现异常时,允许强行撤销一个线程。
  对于在用户空间运行的线程池,由于它完全在用户空间中运行,操作系统内核对线程池不可见,而仅仅知道管理的是一般的单线程进程。这种情况下,线程池起到一个微内核的作用,实质上是多线程应用程序的开发和运行支撑环境。其优点是:节省了内核的宝贵资源,减少系统态和用户态之间的切换,因而,线程池的运行开销小、效率高;容易按特定应用的需要选择进程调度算法,也就是说,线程池的线程调度算法与操作系统的低级调度算法是无关的;能在任何操作系统上运行。其缺点是:当线程执行一个系统调用时,不仅该线程被阻塞,而且,进程内的所有线程会被阻塞,这种多线程应用就不能充分利用多处理器的优点。
  在内核中运行的线程池,则是通过内核来管理线程池的。内核中不但要保存进程的数据结构,也要建立和维护线程的数据结构及保存每个线程的入口,线程管理的所有工作由操作系统内核来实现。由内核专门提供一组应用程序编程接口(API),供开发者开发多线程应用程序。其优点是:能够调度同一进程中多个线程同时在处理器上并行执行,充分发挥多处理器的能力,若进程中的一个线程被阻塞了,内核能调度同一进程的其他线程占有处理器的运行,也可以调度其他进程中的线程运行。其缺点是:在同一进程中,控制权从一个线程传送到另一个线程时需要用户态-系统态-用户态的模式切换,系统开销较大。

原创粉丝点击