By cszhao1980
1. 轻量进程(LWP)
我们知道进程拥有大量资源,如:
(1)寄存器信息,如pc等;
(2)Data段
(3)Stack;
(4)正文段(可与其他进程共享);
(5)open 的file;
(6)信号;
(7)etc。
在进行context switch时,os必须妥善的保存进程的各种资源,开销较大,故进程有也被称为重量进程(HWP)。传统的
操作系统中的并发由进程构成,其缺点有二:
(1)正如前面所说,其context switch的开销较大;
(2)进程间难以进行数据和资源的共享(事实上,这也是其优点之一)。
因此,人们逐步提出了线程的概念,其特点是掌控的资源较少,从而减少了thread switch的开销,故thread也被成为轻量进程。
线程拥有的资源主要有两个:
(1)寄存器信息;
(2)一些状态新型;
【注】:线程自己的Stack往往属于进程stack的一部分,switch时通常无需专门进行保存。
而在thread switch时,往往只需要保存寄存器信息,故switch的开销较小。而由于thread与进程共享大量资源,线程间的通讯
就要容易的多。
2. user level 与kernel level
线程的实现分为两种方式,user Level实现,和kernel Level实现。
所谓user Level的线程实现,指操作系统内核对Thread一无所知,它仍然以进程为单位进行调度。而线程以及线程调度,
完全由user进程完成。我们可以简单理解为user进程又实现了自己的一个“内核”,通过它进行线程调度。
比如,OS分给进程一个50毫秒的时间片,user进程可以将其分为5个10毫秒的小时间片,轮流安排5个线程运行。
User level thread的最大优点是,它真正实现了低消耗的thread switch——事实上,前面一直提到的低消耗指的就是同一
进程内的thread switch;不同进程间的Thread switch等同于进程switch。
它的另一个优点是,可以针对不同的应用灵活的设计switch策略,从而针对不同的应用进行优化。
但user Level也有其不可避免的缺陷,比如,由于操作系统不参与其中,无法使用os提供的各种便利,
比如,thread block时,会导致整个进程被block。当然,我们可以采用不同的手段来弥补这些缺陷,比如,对thread block,
可在编译器的协助下,对各种系统调用进行特殊的包装,比如将IO操作替换为相应的异步版本等等。但总的来说,很难完全
避免这些缺陷。
Kernel Level就比较好理解了,kernel明晰thread的存在并以thread为单位进行调度。 同样,kernel Level也有其优缺点,总
的来说它与user level基本属于“逆”的关系,它很好弥补了user Level的缺陷,但却在user level的长处上载了跟头。当然,
我们也可用通过一定的手段来弥补它的缺陷,比如在设计调度算法时,将thread的隶属关系也考虑进来,尽量安排同进程间
的thread switch。但总的来说,其缺陷也难以完全弥补。
我们还可用混合使用这两种模式,即在kernel线程的基础上,为某些应用采用user level的Thread调度,从而达到更好的使用效果。
在讨论线程模型时,我们还会看到另一套术语,如一对一,多对一和多对多。粗略说来,这套术语和前面所说基本上时一一对应的:
(1)一对一即kernel level的线程模型,一个线程是一个调度单元;
(2)多对一即user level的线程模型,调度以进程为单位,对应user态的多个线程;
(3)多对多即混合模式,内核中的线程在user态可调度多个user态的线程。
3. Linux线程模型概述
Linux的发展过程中,出现过很多个不同的线程库实现。其中两个实现先后成为了标准,即早期的LinuxThread库和后来的NPTL库。
LinuxThread采用一对一模型,它使用clone系统调用来产生“线程”——这里的线程加了引号,这是因为,它实在难以被看作是
传统意义上的线程。一方面,通过设置参数,可以使新生的线程与父进程共享资源,确实符合轻量进程的定义;但另一方面,它
又具备了进程的若干特性,如拥有独立的进程id和信号机制等等。事实上,在这种实现中linux kernel在进行调度时,仍然按照传
统的进程调度机制,在这个意义上,是将“线程”当作进程来处理的。
这样的实现有一些缺陷,比如:
(1)首先它不完全符合POSIX标准,比如在信号处理方面,它是基于“线程”的;
(2)基于clone的实现使其多线程程序移植困难;
(3)由于内核实际上将线程“认作”进程,因此针对进程的诸多限制也被应用在线程上,
比如可用进程总数等等;
为改正这些缺陷,一个新的线程库被发展起来,即red hat开发的NPTL库。NPTL符合 POSIX 标准,且与LinuxThreads 相比,在性能
和稳定性方面也提供了重大的改进。自2.6内核以来,NPTL取代LinuxThreads成为了新的Linux线程标准。
需要注意的是使用2.6(或更好)内核并不等于使用了NPTL,有些发行版会同时携带NPTL和LinuxThreads,而使用哪个库是可以配置
的。用下面的命令可以查看你的系统上正在使用实现:
>getconf GNU_LIBPTHREAD_VERSION
在笔者的fedora 17系统中,显示为“NPTL 2.15”。 您的呢?