3.2.6 线程
自从引入进程概念以来,操作系统把进程作为独立运行的基本单位。进程既是资源申请的独立单位,又是系统调度的独立单位。进程的引入大大地提高了资源的利用率和系统的吞吐量,但是进程在创建、撤销和切换时会造成很大的开销。
1.线程
为了减少程序并发执行时所付出的时空开销,使操作系统具有更好的并发性,现代操作系统将资源分配和调度分离开来,让进程仍作为资源分配的单位,引入比进程粒度更小的独立运行单位——线程(thread),作为系统调度的单位,以便进一步提高程序执行的并发度,减少系统开销。
线程也称为轻载进程(light weight process)。在支持线程的操作系统中,线程是进程中能够并发执行的一个实体,是进程的组成部分,是处理器调度和分派的基本单位。线程只拥有一些在运行中必不可少的资源(如程序计数器、一组寄存器和栈),它与同属于一个进程的其他线程共享该进程拥有的全部资源。各个线程可以并发地运行。线程切换时只需保存和设置少量的寄存器内容,并不涉及存储器管理方面的操作,所以线程切换的开销远远小于进程切换。同一个进程中的多个线程共享同一个地址空间,使得它们之间同步和通信的实现也比较容易。
2.线程实现机制
操作系统提供多种线程的实现机制,基本的两种是内核级和用户级实现。
(1)用户级线程
用户级线程(User Level Thread,ULT)是在用户(目态)空间实现的,是建立在用户进程内的线程,由对应的应用程序通过存放在用户空间的一组管理线程的过程(即线程库)完成对线程的管理工作。ULT的特点为:ULT与内核无关,因此,同一进程中的ULT的调度和切换简单而快速;虽然内核不知道用户级线程的存在,但却管理着该线程所属进程的活动,如果该用户级线程调用了系统调用而处于运行态,那么所属进程还是该阻塞时要阻塞,即线程状态与进程状态是独立的;如果内核阻塞了一个进程,则该进程中所有的线程都将被阻塞;内核只将处理器分配给进程,因此每次只有一个进程中的一个线程在一个处理器上运行。
(2)内核级线程
内核级线程(Kernel Level Thread,KLT)是在核心空间实现的,通过系统调用,由操作系统创建,是依赖于系统内核的线程。由操作系统内核完成对线程的管理工作。线程是CPU调度的基本单位,操作系统为每个线程保持一个核心栈。KLT可以在用户进程中,也可以在系统进程中。
KLT的特点:同一进程中的KTL切换需要进入核心模式下才能完成;当进程中的一个线程被阻塞时,进程中的另一个线程可以被调度;内核可以调度进程中的多个线程,使其同时在多个CPU上并行运行;内核本身也都可以使用多线程方式编写,从而改善操作系统本身的并行性。
除了内核级和用户级线程之外,还可以采用将两者混合的实现机制。即线程的实现分为两个层次:用户层和核心层。内核必须支持内核级线程的创建、调度和管理,同时也允许应用程序创建、调度和管理用户级线程。线程的创建、调度、同步通常在用户空间完成,某个应用程序的多个ULT能分配和对应于一个或多个KLT,KLT可同时并行运行于多个CPU,且在阻塞一个ULT时,内核可调度另一个线程执行。
3.线程模型
线程模型就是指操作系统内线程的实现策略,一般有一对一、多对一和多对多3种模型。
(1)一对一模型
将每个ULT映射到一个KLT,它能够保障并发性,但是对能支持的线程总数有一定的限制。
(2)多对一模型
将多个ULT映射到一个KLT。线程管理在用户空间中进行,效率较高。虽然它能创建很多ULT,但内核一次只能调度一个线程执行,因此,并发性得不到保障。
(3)多对多模型
将多个ULT映射到同样数量或较少数量的KLT。它很好地解决了上面出现的问题,能够创建需要的线程,并且内核也能并行执行这些线程。