我们都知道,在操作系统中,线程是比进程更轻量级的调度执行单位,线程的引入可以把一个进程的资源分配和执行调度分开,各个线程既可以共享进程资源,又可以独立调度。
其实,线程的实现方式主要有三种:分别是使用内核线程实现、使用用户线程实现以及使用用户线程加轻量级进程混合实现。
内核线程(Kernel-Level Thread,KLT)就是直接由操作系统内核(Kernel)支持的线程,这种线程由内核来完成线程切换,内核通过操纵调度器(Scheduler)对线程进行调度,并负责将线程的任务映射到各个处理器上,并向应用程序提供API接口来管理线程。
应用程序一般不会直接去使用内核线程,而是去使用内核线程的一种高级接口——轻量级进程(Light Weight Process,LWP),轻量级进程就是我们通常意义上所讲的线程,由于每个轻量级进程都由一个内核线程支持,因此只有先支持内核线程,才能有轻量级进程。
有了内核线程的支持,每个轻量级进程都成为一个独立的调度单元,即使有一个轻量级进程在系统调用中阻塞了,也不会影响整个进程继续工作。
但是轻量级进程具有它的局限性:首先,由于是基于内核线程实现的,所以各种线程操作,如创建、析构及同步,都需要进行系统调用。而系统调用的代价相对较高,需要在用户态(User Mode)和内核态(Kernel Mode)中来回切换。其次,每个轻量级进程都需要有一个内核线程的支持,因此轻量级进程要消耗一定的内核资源(如内核线程的栈空间),因此一个系统支持轻量级进程的数量是有限的。
在用户空间建立线程库,通过运行时系统(Run-time System)来完成线程的管理,因为这种线程的实现是在用户空间的,所以操作系统的内核并不知道线程的存在,所以内核管理的还是进程,所以这种线程的切换不需要内核操作。
这种实现方式下,进程和线程之间的关系是一对多的。
这种线程实现方式的优点是线程切换快,并且可以运行在任何操作系统之上,只需要实现线程库就行了。但是缺点也比较明显,就是所有线程的操作都需要用户程序自己处理,并且因为大多数系统调用都是阻塞的,所以一旦一个进程阻塞了,那么进程中的所有线程也会被阻塞。还有就是多处理器系统中如何将线程映射到其他处理器上也是一个比较大的问题。
还有一种混合实现的方式,就是线程的创建在用户空间完成,通过线程库进行,但是线程的调度是由内核来完成的。多个用户线程通过多路复用来复用多个内核线程。这个就不展开讲了。