线程
引入线程的动机
为了解决单处理机环境下的程序并发执行问题,设计出多道程序 OS 时引入了进程的概念,此时进程作为能拥有资源和独立调度的基本单位的。由于进程是一个资源的拥有者,因而在创建、撤消和切换中,系统必须为之付出较大的时空开销。因此在原来的 OS 中设置进程的数目不能太多,而且进程切换也不宜过于频繁。
后来为了进一步提高程序并发执行的程度,提出了比进程更小的基本单位——线程。线程的特点在于当线程切换时,仅需保存和设置少量寄存器内容,同时线程的切换不会引起进程的切换。如此把调度和资源的占用分开,使得线程的切换的开销小于进程切换的开销。但从一个进程中的线程切换到另一个进程中的线程时,仍然会引起进程的切换。引入进程之后线程是程序执行流的最小单位,是一个基本的 CPU 执行单元。
线程的特点
在引入线程的 OS 中,在一个进程中的多个线程之间亦可并发执行,这样就进一步提高了 OS 的并发性。进程可以拥有资源,并作为系统中拥有资源的一个基本单位。线程本身并不拥有系统资源,仅持有一点必不可少的、能保证独立运行的资源,引入线程后进程只作为出 CPU 外的系统资源的分配单元。同一进程中的不同线程共享进程的内存地址空间和资源,因此线程的独立性会比进程的独立性低,因为进程之间的资源是相互独立的。在多处理机的系统中,可以将一个进程中的多个线程分配到多个处理机上并行执行,使得执行效率进一步提高。
和进程的对比
- 在调度方面,引入线程的操作系统中线程是独立调度的基本单位,进程是拥有资源的基本单位。在同一个进程中线程的切换不会引起进程切换,在不同的进程中进行线程切换才会引起进程切换;
- 在资源方面,进程是拥有资源的基本单位,线程仅拥有必不可少的系统资源,可以访问进程拥有的系统资源;
- 在并发方面,引入线程后不仅进程之间可以并发执行,线程之间也可以并发执行,使得操作系统具有更好的并发性;
- 在系统开销方面。进程的创建和撤销时,系统都要分配或回收进程的资源,在进程切换时将要保存原进程的运行环境和新进程的创建。线程切换时只需要保存和设置少量的寄存器内容,开销很小,而且同一个进程内的多个线程可以共享进程的地址空间,线程的同步和通信的实现非常方便。
线程的状态
线程的状态和进程很像,各个线程之间也有共享资源和相互合作的制约关系。线程的 3 个基本状态如下:
状态 | 说明 |
---|---|
执行状态 | 线程已获得处理机且正在运行 |
就绪状态 | 线程已具备了各种执行条件,只须再获得 CPU 便可立即执行 |
阻塞状态 | 线程在执行中因某事件受阻而处于暂停状态 |
线程状态的转换和进程一样,如图所示。
应用程序在启动时,执行“初始化线程”创建新线程,此时利用一个线程创建函数(或系统调用)并提供相应的参数。在线程的创建函数执行完后,将返回一个线程标识符供以后使用。当一个线程完成了自己的任务(工作)或被强行终止时,由终止线程通过调用相应的函数(或系统调用)对它执行终止操作。
线程控制块 TCB
每个线程配置了一个线程控制块 TCB,所有用于控制和管理线程的信息记录在线程控制块中。线程控制块有如下信息:
信息 | 说明 |
---|---|
线程标识符 | 每个线程赋予一个唯一的线程标识符 |
一组寄存器 | 包括程序计数器、状态寄存器和通用寄存器的内容 |
线程运行状态 | 描述线程正处于何种运行状态 |
优先级 | 描述线程执行的优先程度 |
线程专有存储区 | 在线程切换时存放现场统计信息和保护信息 |
信号屏蔽 | 对某些信号加以屏蔽 |
堆栈指针 | 将每次过程调用中所使用的局部变量以及返回地址保存起来 |
进程的实现方式
内核支持线程 KST
无论是系统进程还是用户进程,都是在操作系统内核的支持下运行的。在内核支持线程的环境下,内核根据 TCB 感知某线程的存在,并对其加以控制。KST 的优点有:
- 在多处理器系统中,内核能够同时调度同一进程中的多个线程并行执行;
- 如果进程中的一个线程被阻塞了,内核可以调度该进程中的其它线程占有处理器运行;
- 内核支持线程具有很小的数据结构和堆栈,线程的切换比较快且开销小;
- 内核也可以采用多线程技术,提高执行的效率。
主要缺点是对于用户的线程切换而言开销较大,在同一个进程中从一个线程切换到另一个线程时,需要从用户态转到核心态进行。
用户级线程 ULT
用户级线程是在用户空间中实现的,由应用程序通过线程库实现。所有的线程管理都由应用程序负责,无需 OS 进行干预,因此内核完全感知不到用户级线程的存在。ULT 的优点有:
- 线程切换不需要转换到内核空间,所有线程的管理数据结构均在该进程的用户空间中;
- 在不干扰 OS 调度的情况下,不同的进程可以根据自身需要选择不同的调度算法;
- 用户级线程的实现与 OS 平台无关;
用户级线程方式的缺点在于,当线程执行一个系统调用时,会阻塞进程内的所有线程会被阻塞。同时内核每次分配给一个进程的仅有一个 CPU,因此进程中仅有一个线程能执行。
多组合方式
有些 OS 把用户级线程和内核支持线程两种方式进行组合,在组合方式线程系统中内核支持多个内核支持线程的建立、调度和管理,同时也允许用户应用程序建立、调度和管理用户级线程。用户级线程和内核支持线程连接方式的不同可以分成三种不同的模型。
多对一模型
第一种是多对一模型,将用户线程映射到一个内核控制线程,该模型的系统中线程在用户空间进行管理,效率相对更高。但是由于多个用户级的线程映射到一个内核级的线程上,因此只要一个用户级线程被阻塞,整个进程都会被阻塞。而且由于系统智能识别一个内核级线程,所以即使存在多个处理器,该进程的多个用户级线程也不能并行执行。
一对一模型
第二种是一对一模型,将每一个用户级线程映射到一个内核支持线程,这样当一个线程被阻塞时将不会影响其他线程的运行,在多处理器上可以实现多线程并行。一对一模型的并发性比多对一模型好,但是每创建一个用户级线程还要额外在创建一个内核级线程。
多对多模型
第三种多对多模型,即将许多用户线程映射到同样数量或更少数量的内核线程上,一般来说内核级线程的数量不会多于用户级线程。多对多模型能够克服前两种模型的缺点,可以使多个用户级线程并行执行,且不会限制用户级线程的数量。多个内核级线程根据需要调用用户级线程,当一个用户级线程被阻塞时也可以调度其他线程。