LWP 轻量级进程的理解

Definition:a LWP runs in user space on top of a single kernel thread and shares its address space and system resources with other LWPs within the same process

即:轻量级进程(LWP)是建立在内核之上并由内核支持的用户线程,它是内核线程的高度抽象,每一个轻量级进程都与一个特定的内核线程关联。

从语句的结构上我们可以抽象出轻量级进程最基本的概念:是一个用户线程,但是与普通用户线程不同的是,它是由内核支持的,并于内核线程相关联的。

于是我们就可以引出第一个Question:为什么要在普通用户线程的基础上再增加内核支持这个功能?能带来什么好处?

在此我们选择《Understanding the Linux Kernel》这本书中的一个例子进行说明:

假设一个人机大战象棋程序使用两个线程:其中一个控制图形化棋盘,等待人类选手的移动并显示计算机的移动,而另一个思考棋的下一步移动。尽管第一个线程等待选手移动时,第二个线程应当继续运行,以利用选手的思考时间。但是,如果象棋程序仅是一个单独的进程,第一个线程就不能简单地发出等待用户行为的阻塞系统调用;否则,第二个线程也被阻塞。因此,第一个线程必须使用复杂的非阻塞技术来确保进程仍然是可运行的。

在这个例子中很好地指出了如果只使用用户进程的痛点:我们知道对于内核而言,它所能看到的只有进程,而我们所谓的用户线程只是我们人为在进程中创建的执行流,它的创建处理与调度都是在(进程的)用户空间执行(对于执行流的个人理解:对于传统程序的执行即为通过指针在程序中读取相关数据,并传入到cpu进行相关寻址与运算操作,那如果可以创建多个这样的指针,依次往cpu中传入值(在此假设的背景是单Cpu情况下),从而实现多个执行流——即线程的逻辑?)。也就是说内核只能看到进程,而用户线程只是进程用户空间内部的实现逻辑,内核是无法看到的。这也就导致了一个问题:类似中断等资源只能以进程为单位进行执行,不能以用户线程为单位进程执行。

有了上面的概念,我们再来看书中的这个例子。正常来说第一个线程在无用户输入的等待状态时,应该让第二个线程执行(即节约时间进行思考)。然后用户输入作为一个外部输出,产生中断唤醒线程一的执行。但是,由于是线程,线程1并不享有专门中断的权利,故上述的流程是无法实现的。那如果我们退而求其次呢?我们就让线程1一直等着用户输入,我们可以发现由于线程1堵塞等待用户输入(即霸占CPU资源),导致线程2无法获取CPU资源也堵塞(假设的情况仍然是单CPU下)。这导致在获取用户输入后,应用程序做出决策的时间大大延长。很明显这不是我们想要的

所以就开始设想:能不能使用户线程可以专门拥有中断呢?

接着上面的问题继续引出思考:为什么用户线程不能专门拥有中断?———是因为内核并不认识这个线程,所以不能单独给他分配中断。那将他与内核线程(后续会讲)相关联,内核就认识我们这个用户线程了。所以问题也就迎刃而解。

有了上面的引入,我们再来看上面的定义就能更容易理解。我们也可以把上述当作LWP诞生的背景

轻量级进程(LWP)是建立在内核之上并由内核支持的用户线程,它是内核线程的高度抽象,每一个轻量级进程都与一个特定的内核线程关联。

特点分析:

由于本质是用户线程:故轻量级进程可以共享诸如地址空间,打开的文件等,只要其中一个修改共享资源,另一个就立即查看这种修改

同时由于与内核进程相关联:所以每个LWP都可以作为独立单元由Kernel独立调度,同时由于内核线程位于Kernel,而Kernel正是所有资源的管理者,这也LWP也就可以像独立进程一样享有专门的中断。

思考:从上述我们有种感觉:LWP聚集了用户线程共享与内核线程管理的特点。但是我们知道凡事都有自己的优缺点。

  • 首先,大多数LWP的操作,如建立、析构以及同步,都需要进行系统调用。系统调用的代价相对较高:需要在user mode和kernel mode中切换。
  • 每个LWP都需要有一个内核线程支持,因此LWP要消耗内核资源(内核线程的栈空间)。因此一个系统不能支持大量的LWP。

总结:其实网上关于进程与线程的相关争议还是蛮大的,个人认为可能是讨论的角度不对:有些人是在从user_space的角度看,而有些人是在从kernel_space的角度看。就像用户线程与LWP的关系,一开始的时候我认为他们其实是两个完全不同的种类。但是觉得可能更像一个东西的两个不同角度:从kernel看,其实看到的就是LWP,而从用户态看其实就是我们所说的用户线程。或者说LWP是Linux在不断升级的过程中,对用户线程进行更好支持的一种手段,他的出现使得内核中的最小调度单元从process变成了thread(因为LWP的出现,使得kernel可以认识线程)。这样的话,我们也可以更好的理解”线程是内核调度的最小单位“这句话。同时也正是因为LWP的存在,内核可以认识到用户态的线程,以使得线程可以在SMP的环境下发挥出更大的优势(如果一个程序代表一个进程的话,相当于把程序分成好多块在不同的核上运行,提高速度),同时用户线程的并发性得到了很大提升,如果一个线程block住,schedule的控制权在内核手中,内核可以调度组内的其他线程运行

end

Comments

留言