2.7 线程 2.7.1线程的其本概念
引入线程的目的: 提高系统的执行效率,减少处理机的空转时间和调度切换(保护现场信息)的时间,便于系统管理。(减少程序并发执行时所付出的时空开销,使OS具有更好的并发性。)
分析说明: 进程的两个基本属性: 1 进程是一个可拥有资源的独立单位; 2 进程又是一个可独立调度和分配的基本单位。合起来,进程便成为一个能独立运行的基本单位,从而构成了程序并发执行的基础。 简言之,由于进程是一个资源的拥有者,在执行这些操作时会付出较大的时间开销。因此在系统中所设的进程数目不宜过多,切换不宜过于频繁,这就限制了系统的并发程度。
解决问题的基本思路: •把进程的两项功能--“独立分配资源”与“被调度分派执行”分离开来, •进程作为系统资源分配和保护的独立单位,不需要频繁地切换; •线程作为系统调度和分派的基本单位,能轻装运行,会被频繁地调度和切换,在这种指导思想下,产生了线程的概念。
线程的定义 定义:线程是进程中的一个实体,是被系统独立调度和分配的基本单位,故又称为轻权(轻型)进程(Light Weight Process),它由线程控制表、存储线程上下文的用户栈以及核心栈组成。{传统的进程称为重型进程(Heavy Weight Process)。}
线程与进程的主要区别 1进程是资源管理的基本单位,它拥有自己的地址空间和各种资源;线程只是处理机调度的基本单位,它只和其他线程一起共享进程资源,它自己没有任何资源。 2以进程为单位进行处理机切换和调度时,处理机切换时间长,资源利用率降低。以线程为单位进行进行处理机切换和调度时,由于不发生资源变化,特别是地址空间的变化,处理机切换时间较短,从而处理机效率较高。
3对用户来说,多线程系统比无线程系统可减少用户的等待时间,提高系统的响应速度。 4线程和进程一样,都有自己的状态,也有相应的同步机制,不过由于线程没有单独的数据和程序空间,因此线程不能像进程的数据与程序那样,交换到外存存储空间,从而线程没有挂起状态。
5进程的调度、同步等大多由OS内核完成,而线程的控制既可以由OS内核进行,也可以由用户控制。
MS-DOS支持单用户进程,进程是单线程的; 传统UNIX支持多用户进程,进程是单线程的。 很多著名操作系统都支持多线程(结构)进程,如:Solaris 、Mach 、SVR4、OS/390、OS/2、WindowNT、Chorus等; JAVA的运行引擎则是单进程多线程的例子。
线程的属性 1)轻型实体 2)独立调度和分派的基本单位 3)可并发执行 4)共享进程资源
线程主要组成 •当线程不运行时,有一个受保护的线程上下文, 用于存储现场信息。所以,线程也可被看作是执行在进程内的一个独立的程序计数器; •线程执行状态(运行、就绪、…); •当线程不运行时,有一个受保护的线程上下文, 用于存储现场信息。所以,线程也可被看作是执行在进程内的一个独立的程序计数器; •一个执行堆栈 •一个容纳局部变量的主存存储区。
线程的状态(1) 线程状态有:运行、就绪和阻塞,线程的状态转换也类似于进程。 线程的状态(1) 线程状态有:运行、就绪和阻塞,线程的状态转换也类似于进程。 挂起状态对线程是没有意义的,如果进程挂起后被对换出主存,则它的所有线程因共享了进程的地址空间,也必须全部对换出去。
线程的状态(2) 处于运行态的线程阻塞时,对某些线程实现机制,所在进程也转换为阻塞态,即使这个进程存在另一个处于就绪态的线程; 对另一些线程实现机制,如果存在另外一个处于就绪态的线程,则调度该线程处于运行状态,否则进程才转换为阻塞态。
线程又称轻量进程 •系统调度的基本单位是线程而不是进程,每当创建一个进程时,至少要同时为该进程创建一个线程,否则该进程无法被调度执行。 •线程运行在进程的上下文中,并使用进程的资源和环境。 •系统调度的基本单位是线程而不是进程,每当创建一个进程时,至少要同时为该进程创建一个线程,否则该进程无法被调度执行。
多线程环境中的进程与线程 单线程进程的内存布局和运行 进 程 单线程进程(模型) 用户 地址空间 进程 控制块 堆栈 系统 进程控制块 单线程进程的内存布局和运行 进程控制块 进 程 用户地址空间 用户堆栈 系统堆栈 管理者 执行序列 单线程进程(模型) 用户 地址空间 进程 控制块 堆栈 系统
多线程进程的内存布局 多线程进程模型 用户 地址空间 进程 控制块 线程控制块 系统 堆栈 线程1 线程N
多线程环境中进程的定义 •一个虚拟地址空间,用来容纳进程的映像; •对处理器、其他(通信的)进程、文件和I/O资源等的存取保护机制。 进程是操作系统中进行保护和资源分配的基本单位。它具有: •一个虚拟地址空间,用来容纳进程的映像; •对处理器、其他(通信的)进程、文件和I/O资源等的存取保护机制。
多线程环境中的线程概念 线程是操作系统进程中能够独立执行的实体(控制流),是处理器调度和分派的基本单位。线程是进程的组成部分,每个进程内允许包含多个并发执行的实体(控制流),这就是多线程。
线程库 多线程的操作系统和语言都提供了线程库,如Mach的C-threads和Java线程库,支持应用程序创建、调度、和管理用户级线程的运行。 线程库实质上是多线程应用程序的开发和运行支撑环境。线程库至少应提供以下功能:孵化、封锁、活化、结束、通信、同步、调度等。每个线程库应提供给用户级的API编程使用。
线程管理和线程库(1) 多线程技术利用线程包(库)提供线程原语集来支持多线程运行, 有的操作系统直接支持多线程,而有的操作系统不支持多线程。 线程包(库)可分成两种:用户空间中运行的线程包(库)和内核中运行的线程包(库)。
线程管理和线程库(2) •孵化(Spawn):又称创建线程。 •封锁(Block):又称阻塞线程。 •活化(Unblock):又称恢复线程。 线程包(库)提供一组API,支持应用程序创建、调度、撤销和管理线程的运行。基本线程控制原语: •孵化(Spawn):又称创建线程。 •封锁(Block):又称阻塞线程。 •活化(Unblock):又称恢复线程。 •结束(Finish):又称撤销线程。
2.7.2线程间的同步与通信 1.互斥锁 2.条件变量 3.信号量机制
2.3 线 程 给每个进程分配一虚拟地址空间,保存进程映像,控制一些资源(文件,I/O设备),有状态、优先级、调度 进程是一个执行轨迹 2.3 线 程 1.进程的两个基本属性: 资源的拥有者: 给每个进程分配一虚拟地址空间,保存进程映像,控制一些资源(文件,I/O设备),有状态、优先级、调度 调度单位: 进程是一个执行轨迹 以上两个属性构成进程并发执行的基础
2. 线程的引入 对进程系统必须完成的操作: 创建进程 撤消进程 进程切换 缺点: 时间空间开销大,限制并发度的提高
线程的引入(续1) 线程:有时称轻量级进程,进程中的一个运行实体,是一个CPU调度单位,资源的拥有者还是进程或称任务 在操作系统中,进程的引入提高了计算机资源的利用效率。但在进一步提高进程的并发性时,人们发现进程切换开销占的比重越来越大,同时进程间通信的效率也受到限制 线程的引入正是为了简化进程间的通信,以小的开销来提高进程内的并发程度 线程:有时称轻量级进程,进程中的一个运行实体,是一个CPU调度单位,资源的拥有者还是进程或称任务
线程的引入(续2) 线程: 有执行状态(状态转换) 不运行时保存上下文 有一个执行栈 有一些局部变量的静态存储 可存取所在进程的内存和其他资源 可以创建、撤消另一个线程
3. 线程的特点 是进程的一个实体,可作为系统独立调度和分派的基本单位。 不拥有系统资源(只拥有从属进程的全部资源,资源是分配给进程) 一个进程中的多个线程可并发执行。(进程可创建线程执行同一程序的不同部分) 系统开销小、切换快。(进程的多个线程都在进程的地址空间活动)
4.线程和进程的关系 单进程、单线程 单进程、多线程 多进程、一个进程一个线程 多进程、一个进程多个线程
包含了寄存器映像,线程优先数和线程状态信息 P C B 用 户 栈 单线程进程模型 用户地址空间 核 心 线程控制块: 包含了寄存器映像,线程优先数和线程状态信息
P C B 多线程进程模型 用户 地址 空间 用 户 栈 核 心 线程 控制块
5.引入线程的好处 创建一个新线程花费时间少(结束亦如此) 两个线程的切换花费时间少 (如果机器设有“存储[恢复]所有寄存器”指令,则整个切换过程用几条指令即可完成) 因为同一进程内的线程共享内存和文件,因此它们之间相互通信无须调用内核 适合多处理机系统
例子1: LAN中的一个文件服务器,在一段时间内需要处理几个文件请求 因此有效的方法是:为每一个请求创建一个线程 在一个SMP机器上:多个线程可以同时在不同的处理器上运行
例子2: 一个线程显示菜单,并读入用户输入; 另一个线程执行用户命令 考虑一个应用:由几个独立部分组成,这几个部分不需要顺序执行,则每个部分可以以线程方式实现 当一个线程因I/O阻塞时,可以切换到同一应用的另一个线程
6.线程与进程的比较 调度:线程作为调度的基本单位,同进程中线程切换不引起进程,当不同进程的线程切换才引起进程切换;进程作为拥有资源的基本单位。 并发性:一个进程间的多个线程可并发。 拥有资源:线程仅拥有隶属进程的资源;进程是拥有资源的独立单位。 系统开销:进程大;线程小。
7. 线程的实现机制 用户级线程 核心级线程 两者结合方法
1) 用户级线程(ULT) 由应用程序完成所有线程的管理 通过线程库(用户空间) 一组管理线程的过程 核心不知道线程的存在 线程切换不需要核心态特权 调度是应用特定的
对用户级线程的核心活动 即线程状态是与进程状态独立的 核心不知道线程的活动,但仍然管理线程的进程的活动 当线程调用系统调用时,整个进程阻塞 但对线程库来说,线程仍然是运行状态 即线程状态是与进程状态独立的
用户级线程的优点和缺点 优点: 线程切换不调用核心 调度是应用程序特定的:可以选择最好的算法 ULT可运行在任何操作系统上(只需要线程库) 缺点: 大多数系统调用是阻塞的,因此核心阻塞进程,故进程中所有线程将被阻塞 核心只将处理器分配给进程,同一进程中的两个线程不能同时运行于两个处理器上
2) 核心级线程(KLT) 所有线程管理由核心完成 没有线程库,但对核心线程工具提供API 核心维护进程和线程的上下文 线程之间的切换需要核心支持 以线程为基础进行调度 例子:Windows NT,OS/2
核心级线程的优点和缺点 优点: 对多处理器,核心可以同时调度同一进程的多个线程 阻塞是在线程一级完成 核心例程是多线程的 缺点: 在同一进程内的线程切换调用内核,导致速度下降
两者分析 针对不同的操作系统 开销和性能(线程的调度和切换速度) 系统调用(阻塞) 线程执行时间 灵活性 可扩充性 抢占CPU 共享进程的资源
3) ULT和KLT结合方法 线程创建在用户空间完成 大量线程调度和同步在用户空间完成 程序员可以调整KLT的数量 可以取两者中最好的 例子:Solaris
实例:Solaris 进程: 用户地址空间 用户栈 进程控制块
分派 唤醒 继续 抢占 停止 可运行 睡眠 用户级线程 活跃 连接在LWP上
LWP状态独立于状态ULT(受限制ULT除外) 分派 唤醒 继续 时间片 或抢占 停止 运行 阻塞 系统 调用 轻型进程状态 LWP状态独立于状态ULT(受限制ULT除外) 可运行
进程 1 进程 2 进程 3 进程 4 进程 5 进程库 用户 内核 硬件 用户级线程 内核级线程 轻型线程 处理器
8. 线程与进程的关系 线程:进程 特点 例子 每一执行的线程是 有自己的地址空间 和资源的唯一进程. 各种UNIX版本 1 : 1 M : 1 进程定义了所拥有 的地址空间和动态 资源。在该进程中 多个线程可被创建 和执行. Windows NT, Solaris, OS/2, OS/390, MACH
9.用户级线程和内核支持线程 内核支持线程——依赖于内核。(创建、撤消、切换由内核实现) 用户级线程——与内核无关(切换速度特别快,不利用系统调用)
2.7.3内核支持线程和用户级线程 •用户级线程ULT(如Java ,Informix) •内核级线程KLT(如OS/2)。 从实现的角度看,线程可以分成: •用户级线程ULT(如Java ,Informix) •内核级线程KLT(如OS/2)。 •混合式线程(如,Solaris)。
各种线程实现方法 用户空间 线程库 P 内核空间 2)用户级线程 1)内核级线程 3)混合式线程 ULT KLT Process
1. 内核级线程(1) 纯内核级线程设施中,线程管理的所有工作由操作系统内核做。内核专门提供KLT API,应用程序区不需要有线程管理代码。Windows NT 和 OS/2都是采用这种方法的例子。
内核级线程(2) 线程执行中可通过内核创建线程原语来创建其他线程,这个应用的所有线程均在一个进程中获得支持。 内核要为整个进程及进程中的单个线程维护现场信息,应在内核中建立和维护PCB及TCB,内核的调度是在线程的基础上进行的。
内核级线程主要优点 多处理器上,内核能同时调度同一进程中多个线程并行执行。 进程中的一个线程被阻塞了,内核能调度同一进程的其它线程占有处理器运行。 内核线程数据结构和堆栈很小,KLT切换快,内核自身也可用多线程技术实现,能提高系统的执行速度和效率。
内核级线程的主要缺点 应用程序线程在用户态运行,而线程调度和管理在内核实现,在同一进程中,控制权从一个线程传送到另一个线程时需要用户态-内核态-用户态的模式切换,系统开销较大。
2 用户级线程 纯ULT设施中,线程管理工作由应用程序做,内核不知道线程的存在。任何应用程序均需通过线程库进行程序设计,再与线程库连接后运行来实现多线程。 线程库是一个ULT管理的例行程序包,实质上线程库是线程的运行支撑环境。
ULT线程“孵化”过程 进程开始只有一个线程,它可以孵化新线程,通过过程调用把控制权传送给“孵化”过程,由线程库为新线程创建一个TCB,并置为就绪态,按一定的调度算法把控制权传递给进程中处于就绪态的一个线程。当控制权传送到线程库时,当前线程的现场信息应被保存,而当线程库调度一个线程执行时,要恢复它的现场信息。
线程调度和进程调度间的关系(1) 假设进程B正在执行线程3,可能出现下列情况: • 进程B的线程3发出一个封锁B的系统调用(如I/O操作),通知内核进行I/O并将进程B置为等待状态,按照由线程库所维护的数据结构,进程B的线程3仍处在运行态。线程3并不实际地在一个处理器上运行,而是可理解为在线程库的运行态中。这时,进程B为等待态,线程3为线程库运行态。
线程调度和进程调度间的关系(2) •两种情况中,当内核切换控制权返回到进程B时,便恢复执行线程3。 •一个时钟中断传送控制给内核,内核中止当前时间片用完的进程B,并把它放入就绪队列,切换到另一个就绪进程,此时,按由线程库维护的数据结构,进程B的线程3仍处于运行态。这时,进程B己处于就绪态,但线程为线程库运行态。 •两种情况中,当内核切换控制权返回到进程B时,便恢复执行线程3。
ULT优点 •线程切换不需要内核特权方式, •按应用特定需要来调度, •ULT能运行在任何OS上,
ULT的缺点 • 纯ULT中,多线程应用不能利用多重处理的优点。内核在一段时间里,分配一个进程仅占用一个CPU,进程中仅有一个线程能执行。 • 线程执行系统调用时,不仅该线程被阻塞,且进程内的所有线程会被阻塞。 • 纯ULT中,多线程应用不能利用多重处理的优点。内核在一段时间里,分配一个进程仅占用一个CPU,进程中仅有一个线程能执行。
克服上述问题的方法 •第二种方法是采用jacketing技术解决阻塞线程的问题。 •第一种方法是用多进程并发程序设计代替多线程并发程序设计,这种方法事实上放弃了多线程带来的所有优点。 •第二种方法是采用jacketing技术解决阻塞线程的问题。
3 混合式线程 混合系统中,内核支持KLT多线程的建立、调度和管理,也提供线程库,允许应用程序建立、调度和管理ULT。应用程序的多个ULT映射成一些KLT,程序员可按应用需要和机器配置调整KLT数目,以达到较好效果。 一个应用中的多个线程能同时在多处理器上并行运行,且阻塞一个线程时并不需要封锁整个进程。
LWP的数据结构(1) • 轻量进程标识符标识了轻量进程 • 优先数定义了轻量进程执行的优先数 • 信号掩码定义了内核能够接受的信号 • 寄存器域用于存放轻量进程让出处理器时的现场信息 • 轻量进程的内核栈包括每个调用层次的系统调用的参数、返回值和出错码
LWP的数据结构(2) • 用户或用户和系统共同的虚时间警示 • 用户时间和系统处理器使用 • 资源使用和预定义数据 • 交替的信号堆栈 • 用户或用户和系统共同的虚时间警示 • 用户时间和系统处理器使用 • 资源使用和预定义数据 • 指向对应内核线程的指针 • 指向进程结构的指针
ULT的数据结构 • 优先数定义了线程执行的优先数 • 信号掩码定义了能够接受的信号 • 寄存器域用于存放线程让出处理器时的现场信息 • 线程标识符标识了线程 • 优先数定义了线程执行的优先数 • 信号掩码定义了能够接受的信号 • 寄存器域用于存放线程让出处理器时的现场信息 • 堆栈用于存放线程运行数据 • 线程局部存储器用于存放线程局部数据
KLT的数据结构(1) • 内核寄存器数据保存区 • 优先级和调度信息 • KLT的队列指针和堆栈指针 • 相关LWP的指针及信息 • 内核寄存器数据保存区 • 优先级和调度信息 • KLT的队列指针和堆栈指针 • 相关LWP的指针及信息 • 进程数据结构,包括: • 与进程相关的KLT • 进程地址空间指针 • 用户权限表 • 信号处理程序清单 • 与用户执行有关信息
KLT的数据结构(2) Solaris支持实时类进程,内核是可抢占的,内核函数和过程全部用线程实现,Solaris的内核是KLT的集合。 KLT分两种,一种是负责执行一个指定的内核函数;另一种用来支持和运行LWP,KLT是独立被调度和分配到CPU上去执行。
LWP的状态转换 •当ULT处于活跃态时只能捆绑到一个LWP上。只有当LWP处于运行态时,活跃态的ULT才真正处于活跃态并执行。 •当处于活跃态的ULT调用一个阻塞的系统调用时,它对应的LWP进入阻塞状态,这个ULT将继续处于活跃状态并继续与相应的LWP绑定,直到线程库显式地做出变动。