本文主要参考《计算机操作系统(第四版)》(西安电子科技大学出版社)以及清华大学操作系统公开课(向勇、陈渝),整理操作系统的基本概念,供自己复习查阅。
线程(Thread)
线程的引入是为了减少程序在并发执行时的时空开销。
线程的引入
回顾进程的基本属性:
- 进程是一个可拥有资源的独立单位;
- 进程是一个可独立调度和分派的基本单位。
由于进程同时是资源的所有者和调度的基本单位,进程的创建、撤销和切换都要付出较大的时空开销,不利于并发程度的提高。因此,要设法把进程的两个属性分开,让操作系统分别处理。由此也就引入了线程的概念,让线程仅作为调度和分派的基本单位。
线程与进程
线程在调度上与进程很相似,但又有自己的优势所在。
- 线程是调度和分派的基本单位,切换线程时,仅需保存和设置少量的寄存器,代价远低于进程。
- 进程可以并发执行,一个进程内的多个线程也可以并发执行,不同进程的线程也可以并发执行。
- 进程是系统中拥有资源的一个基本单位,线程仅持有保持运行所必不可少的资源(如:线程控制块TCB、程序计数器、少数寄存器和堆栈)。
在引入线程的操作系统中,进程已经不是可执行的实体了,线程才是独立运行的基本单位。但进程仍保留有与执行有关的状态,这些状态用于控制从属于该进程的线程。
线程控制块
与PCB类似,操作系统会维护一个数据结构来保存线程的信息,这就是线程控制块(Thread Control Block,TCB)。通常线程控制块包含线程标识符、程序计数器、状态寄存器、通用寄存器、运行状态、存储区、优先级和堆栈指针。
线程的分类
内核支持线程
内核支持线程(Kernel Supported Threads,KST)是在内核支持下运行的,它的创建、阻塞、撤销、切换都在内核空间实现。
内核支持线程的优点是:
- 内核可以同时调度同一进程的多个线程执行;
- 当线程阻塞时,内核可以调度同进程的其他线程或其他进程的线程占有CPU执行;
- 内核支持线程的数据结构和堆栈很小,线程切换快,切换代价小;
- 内核本身也是多线程并发,进一步提供了速度和效率。
缺点是对用户进程的线程切换开销比较大,需要从用户态切换到核心态。
用户级线程
概念
用户级线程(User Level Threads,ULT)是在用户空间实现的,线程操作与内核无关。对于设置了用户级线程的系统,其调度仍是以进程为单位进行的。一个具体例子是:采用时间片轮转调度时,每个进程轮流执行一个时间片,而不是每个线程。
用户级线程的优点是:
- 线程切换是用户级操作,不需转换到内核空间;
- 进程调度算法可以是进程专用的,不同进程内根据需要选择不同的线程调度算法;
- 用户级线程的实现与操作系统无关,二是属于用户程序的一部分;
缺点是当线程阻塞时,与该线程同属一个进程的线程也会被阻塞;内核只会给一个进程分配一个CPU,即同一进程中只能有一个线程能执行。
实现
用户级线程在用户空间实现,运行在一个中间系统上。目前有两种方式实现中间系统:运行时系统和内核控制线程。
运行时系统
运行时系统实质上是一系列用于管理控制线程的函数的集合,这些函数都驻留在用户空间,作为用户级线程和内核的接口。当线程需要系统资源时,需要先把请求提交给运行时系统,再由运行时系统通过对应的系统调用获得系统资源。
内核控制线程
内核控制线程又叫轻型进程(Light Weight Process,LWP)。每个进程可以拥有多个LWP,每个LWP都有自己的数据结构(类似TCB)。LWP可以通过系统调用获得内核提供的服务,当一个用户级线程运行时,只需把它连接到一个LWP上,它就具有了内核支持线程的所有属性。其实这种实现方式是一种组合方式,它包含了内核支持线程和用户级线程,充分发挥了各自的优点。
由于用户级线程数量往往很大,为了节省系统开销,操作系统通常会把LWP做成一个缓冲池,称为线程池。任一用户线程都可以连接到线程池的任一LWP上,还可以让多个用户级线程多路复用一个LWP。而每个LWP都会连接到一个内核线程上,在内核的角度看,与它交互的总是LWP,它感受不到用户级线程的存在,即实现了内核和用户级线程的隔离。