内核支持线程 & 用户级线程

1.内核支持线程

内核支持线程是什么

各种进程,包括系统进程和用户进程,它们的创建、撤销和I/O操作、切换等,都是使用系统调用进入内核,再由内核的相应处理程序完成的——可以说所有进程都是在OS内核的支持下运行。

内核支持线程(Kernel Supported Threads)就是在内核支持下运行的。使用内核支持线程的情况下,用户进程和系统进程中的线程的创建、撤销和切换都是由内核在内核空间实现。内核空间会为每一个内核支持线程设置一个TCB(线程控制块,Thread Control Block),内核通过TCB感知一个线程的存在

内核支持线程的优缺点

内核支持线程的优点如下:

  • 在多CPU系统中,内核能够把不同的CPU及分配给同一进程的多个线程,提升了运算效率。

  • 如果进程中的一个线程被阻塞了,内核依然可以调度其他线程(本进程和其他进程的线程都可以)运行。

  • 内核支持线程有很小的数据结构和堆栈,切换时在这方面的开销比较小。

  • 内核本身也可以采用多线程技术,来提高系统的速度和效率。

相应地,它也有一些缺点:

  • 系统线程的切换一直在内核态完成,然而用户线程切换时,却需要从用户态转到内核态——这是由于用户线程在用户态运行,而线程调度和管理包括切换却在内核态运行,这种转换会带来较大开销。

内核支持线程的实现

下面说一种在仅设置了内核支持线程的OS中可行的线程控制方法。

  1. 系统在创建一个新进程时,为它在内核空间中分配一个任务数据区(Per Task Data Area, PTDA),里面包括若干个TCB空间。

    TCB存放了线程标识符、优先级、线程运行时的CPU状态等信息。


    image-20200531030431309.png
  1. 每当创建一个新线程时,就为它分配一个TCB,填入有关信息,并为它分配必要的少量资源(如为线程分配数百至数千个字节的栈空间和局部存储区)。

  2. 当PTDA中的所有TCB空间已用完,而进程又要创建新的线程时,只要其所创建的线程数目未超过系统的允许值(通常为数十至数百个),系统可再为这个进程分配新的TCB空间。

  3. 在撤销线程时,收回该线程所有资源和TCB。

在有的系统中为了减少创建和撤消一个线程时的开销,在撤消一个线程时,并不立即回收该线程的资源和TCB,当以后再要创建一个新线程时,便可直接利用已被撤消但仍保持有资源和TCB的线程作为新线程。

2.用户级线程

相比起内核支持线程是在内核空间操作的,用户级线程是存在于用户空间中。

用户级线程与内核没有什么关系,它的创建、撤销、线程间同步与通信,都无需使用系统调用。它的TCB自然也设置在用户空间,因而内核也不知道它的存在。

用户级系统以进程为调度单位

在仅设置了用户级线程的系统里,调度以进程而不是线程为单位,而在仅设置系统级线程的系统里是以线程为单位的。这是它比较傻的地方,由于系统调用需要阻塞进程,当进程里的一个线程执行系统调用时,作为调度单位的整个进程都会被阻塞!而如上所说,内核支持线程中仅阻塞系统调用的线程而其他线程仍然能运行。

而在同样由于以线程为单位的原因,在多CPU系统里,内核每次只能给进程分配一个CPU,在进程里的多个线程就不能同时利用多个CPU了。

既然它有这么多缺点,自然也有许多好处来给人们采用它的理由。上面说到内核支持的用户线程切换时需要在内核态和用户态间切换,而用户级线程并不存在这个问题——所有管理用户级线程的数据结构都在用户空间中,切换也在用户空间完成,可以省一笔切换模式的开销。

另一个有点是用户级线程的实现和OS平台无关——管理线程的一切操作都在用户空间,进程还可以根据自己的需要定义自己专用的线程调度算法,这一切都不与内核的底层实现有什么关系,用户级线程甚至可以在不支持线程机制的操作系统实现!

用户级线程的优缺点

现在我们总结一下上面讲的用户级线程的优缺点:

优点:

  • 线程切换仅在用户空间,不需要在用户态和内核态切换,速度较块

  • OS平台无关,不涉及OS的底层机制,甚至可以在不支持线程机制的OS上实现。

缺点:

  • 某个线程做系统调用时,整个它所属的进程都会被阻塞

  • 多CPU系统下每个进程一次只能分配一个CPU,而不能让进程内的多个线程同时用多个CPU

用户级线程的实现

用户级系统靠一个中间系统实现——运行时系统(Runtime System)。

我们来介绍一下它。运行时系统是一套管理和控制线程的函数集合,里面的各种函数有用于创建和撤销线程的、用于线程同步和通信的、切换线程、其他线程调度的等等。我们把运行时系统所有的函数都存在用户空间,作为与内核的接口——就是说用户级线程只管调用运行时系统的函数,而这些函数会自己解决怎么和内核交流和完成需要的功能。对于不同OS内核,运行时函数要采用不同的底层实现;而对于用户级线程来说调用的都是一样的函数,它与内核是无关的。

需要注意的是,系统资源最终都是由内核管理分配,用户级线程需要资源的时候也是通过调用运行时系统的函数找内核要。

3.组合实现方式

既然内核支持线程和用户级线程都有自己的优缺点,把它们恰当组合起来我们可以扬长避短,得到更好的性能。

这种组合是通过内核控制线程(又称为轻型进程,Light Weight Process,LWP)实现的。

我们使系统拥有若干个内核控制线程,把它们做成一个缓冲池,称为线程池。当一个用户级线程需要内核提供的服务时,就连接到一个内核控制线程上,通过它来获得内核支持。这样一来,用户级线程也有了内核支持的属性,我们就这样把两种线程实现方式组合了起来。

每一个内核控制线程都连接在一个内核支持线程上(有可能多个内核控制线程连接在一个内核支持线程上)。用户级线程要和内核通信时必须等待没有被占用的内核控制线程,如果没有空闲的就阻塞排队。

在内核级线程执行操作时,如果发生阻塞,则与之相连接的多个内核控制线程也将随之阻塞,进而使连接到内核控制线程上的用户级线程也被阻塞。而如果在一个进程中含有多个LWP,则当一个 LWP阻塞时,进程中的其他LWP可继续执行——如果它们连接的内核支持线程没有被阻塞的话。

image-20200531123748545.png

你可能感兴趣的:(内核支持线程 & 用户级线程)