写在前面:
- 本系列笔记主要以《计算机操作系统(汤小丹…)》为参考,大部分内容出于此书,笔者的工作主要是挑其重点展示,另外配合下方视频链接的教程展开思路,在笔记中一些比较难懂的地方加以自己的一点点理解(重点基本都会有标注,没有任何标注的难懂文字应该是笔者因为强迫症而加进来的,可选择性地忽略)。
- 视频链接:操作系统(汤小丹等第四版)_哔哩哔哩_bilibili
一、线程的实现方式
1、内核支持线程KST
(1)在OS中的所有进程,无论是系统进程还是用户进程,都是在操作系统内核的支持下运行的,是与内核紧密相关的,而内核支持线程KST同样也是在内核的支持下运行的,它们的创建、阻塞、撤消和切换等,也都是在内核空间实现的。为了对内核线程进行控制和管理,在内核空间也为每一个内核线程设置了一个线程控制块,内核根据该控制块而感知某线程的存在,并对其加以控制。
(2)这种线程实现方式主要有四个主要优点:
①在多处理器系统中,内核能够同时调度同一进程中的多个线程并行执行。
②如果进程中的一个线程被阻塞了,内核可以调度该进程中的其它线程占有处理器运行,也可以运行其它进程中的线程。
③内核支持线程具有很小的数据结构和堆栈,线程的切换比较快,切换开销小。
④内核本身也可以采用多线程技术,可以提高系统的执行速度和效率。
(3)内核支持线程的主要缺点是:对于用户的线程切换而言,其模式切换的开销较大会一个进程中,从一个线程切换到另一个线程时,需要从用户态转到核心态进行,这是为用户进程的线程在用户态运行,而线程调度和管理是在内核实现的,系统开销较大。
2、用户级线程ULT
(1)用户级线程是在用户空间中实现的。对线程的创建、撤消、同步与通信等功能,都无需内核的支持,即用户级线程是与内核无关的(比如用户级线程的切换在用户态下即可完成,无需操作系统干预)。在一个系统中的用户级线程的数目可以到数百个至数千个。由于这些线程的任务控制块都是设置在用户空间,而线程所执行的操作也无需内核的帮助,因而内核完全不知道用户级线程的存在(用户级线程对用户不透明,对操作系统透明)。
(2)用户级线程方式有许多优点:
①线程切换不需要转换到内核空间。对一个进程而言,其所有线程的管理数据结构均在该进程的用户空间中,管理线程切换的线程库也在用户地址空间运行,因此进程不必切换到内核方式来做线程管理,从而节省了模式切换的开销。
②调度算法可以是进程专用的。在不干扰 OS 调度的情况下,不同的进程可以根据自身需要选择不同的调度算法,对自己的线程进行管理和调度,而与0S的低级调度算法是无关的。
③用户级线程的实现与OS平台无关,因为对于线程管理的代码是属于用户程序的一部分,所有的应用程序都可以对之进行共享。因此,用户级线程甚至可以在不支持线程机制的操作系统平台上实现。
(3)用户级线程方式的主要缺点在于:
①系统调用的阻塞问题。在基于进程机制的OS中,大多数系统调用将使进程阻塞,因此,当线程执行一个系统调用时,不仅该线程被阻塞,而且进程内的所有线程会被阻塞。而在内核支持线程方式中,则进程中的其它线程仍然可以运行。
②在单纯的用户级线程实现方式中,多线程应用不能利用多处理机进行多重处理的优点,内核每次分配给一个进程的仅有一个CPU,因此进程中仅有一个线程能执行,在该线程放弃CPU之前,其它线程只能等待。
3、组合方式
有些OS把用户级线程和内核支持线程两种方式进行组合,提供了组合方式ULT/KST线程。
在组合方式线程系统中,内核支持多个内核支持线程的建立、调度和管理,同时也允许用户应用程序建立、调度和管理用户级线程。一些内核支持线程对应多个用户级线程,这是用户级线程通过时分多路复用内核支持线程来实现的,即将用户级线程对部分或全部内核支持线程进行多路复用,程序员可按应用需要和机器配置,对内核支持线程数目进行调整,以达到较好效果。
组合方式线程中,同一个进程内的多个线程可以同时在多处理器上并行执行,而且在阻塞一个线程时并不需要将整个进程阻塞,所以组合方式多线程机制能够结合KST和ULT两者的优点,并克服了其各自的不足。
由于用户级线程和内核支持线程连接方式的不同,从而形成了三种不同的模型:
①多对一模型:将用户线程映射到一个内核控制线程,这些用户线程一般属于一个进程,运行在该进程的用户空间,对这些线程的调度和管理也是在该进程的用户空间中完成。仅当用户线程需要访问内核时,才将其映射到一个内核控制线程上,但每次只允许一个线程进行映射。该模型的主要优点是线程管理的开销小、效率高;其主要缺点在于,如果一个线程在访问内核时发生阻塞,则整个进程都会被阻塞,此外,在任一时刻只有一个线程能够访问内核,多个线程不能同时在多个处理机上运行。
②一对一模型:将每一个用户级线程映射到一个内核支持线程,为每一个用户线程都设置一个内核控制线程与之连接。该模型的主要优点是当一个线程A阻塞时,允许调度另一个线程运行,所以它提供了比多对一模型更好的并发功能,此外,在多处理机系统中,它允许多个线程并行地运行在多处理机系统上;该模型的唯一缺点是每创建一个用户线程,相应地就需要创建一个内核线程,开销较大,因此需要限制整个系统的线程数。
③多对多模型:将许多用户线程映射到同样数量或更少数量的内核线程上,内核控制线程的数目可以根据应用进程和系统的不同而变化,可以比用户线程少,也可以与之相同。该模型结合上述两种模型的优点,它可以像一对一模型那样,使个进程的多个线程并行地运行在多处理机系统上,也可像多对一模型那样,减少线程的管理开销和提高效率。
二、线程的具体实现
1、内核支持线程的实现
系统在创建一个新进程时,便为它分配一个任务数据区PTDA(Per Task Data Area),其中包括若干个线程控制块TCB空间,在每一个TCB中可保存线程标识符、优先级、线程运行的CPU状态等信息,虽然这些信息与用户级线程TCB中的信息相同,但现在却是被保存在内核空间中。
每当进程要创建一个线程时,便为新线程分配一个TCB,将有关信息填入该TCB中,并为之分配必要的资源,当PTDA中的所有TCB空间已用完,而进程又要创建新的线程时,只要其所创建的线程数目未超过系统的允许值,系统可再为之分配新的TCB空间;在撤消一个线程时,也应回收该线程的所有资源和TCB。
2、用户级线程的实现
用户级线程是在用户空间实现的。所有的用户级线程都具有相同的结构,它们都运行在一个中间系统上,当前有两种方式实现中间系统,即运行时系统和内核控制线程。
①所谓“运行时系统”,实质上是用于管理和控制线程的函数(过程)的集合。
②内核控制线程又称为轻型进程LWP(Light Weight Process),LWP可通过系统调用来获得内核提供的服务。
三、线程的创建和终止
1、线程的创建
应用程序在启动时,通常仅有一个线程在执行,人们把线程称为“初始化线程”,它的主要功能是用于创建新线程。
在创建新线程时,需要利用一个线程创建函数(或系统调用),并提供相应的参数,如指向线程主程序的入口指针、堆栈的大小,以及用于调度的优先级等。在线程的创建函数执行完后,将返回一个线程标识符供以后使用。
2、线程的终止
当一个线程完成了自己的任务(工作)后,或是线程在运行中出现异常情况而须被强行终止时,由终止线程通过调用相应的函数(或系统调用)对它执行终止操作。在大多数的OS中,线程被中止后并不立即释放它所占有的资源,只有当进程中的其它线程执行了分离函数后,被终止的线程才与资源分离,此时的资源才能被其它线程利用。
虽已被终止但尚未释放资源的线程仍可以被需要它的线程所调用,以使被终止线程重新恢复运行,为此,调用线程须调用一条被称为“等待线程终止”的连接命令来与该线程进行连接。如果在一个调用者线程调用“等待线程终止”的连接命令试图与指定线程相连接时,若指定线程尚未被终止,则调用连接命令的线程将会阻塞,直至指定线程被终止后,才能实现它与调用者线程的连接并继续执行;若指定线程已被终止,则调用者线程不会被阻塞而是继续执行。