轻量级进程LWP
在大多数系统中,LWP与普通进程的区别也在于它只有一个最小的执行上下文和调度程序所需的统计信息,而这也是它之所以被称为轻量级的原因。
因为LWP之间共享它们的大部分资源,所以它在某些应用程序就不适用了;这个时候就要使用多个普通的进程了。例如,为了避免内存泄漏(a process can be replaced by another one)和实现特权分隔(processes can run under other credentials and have other permissions)。
标
发信站: 水木社区 (Fri May
难道你说的kernel 2.4?
现在的kernel,线程并不创建process,是真正意义上的线程,各个线程共享一个pid
【 在 youxia (游侠) 的大作中提到: 】
: LINUX的线程都是轻量级进程。难道采用UNIX线程不好吗?
二.Linux线程发展
这个对于理解Linux多线程很有帮助,可惜《深入理解Linux内核》这本书只字未提,根本没讲Linux多线程的机理,至少我没看懂。
一直以来, linux内核并没有线程的概念.
模型一 :LinuxThreads
注:以下内容主要参考“杨沙洲
linux 2.6以前, pthread线程库对应的实现是一个名叫linuxthreads的lib.这种实现本质上是一种LWP的实现方式,即通过轻量级进程来模拟线程,内核并不知道有线程这个概念,在内核看来,都是进程。
Linux采用的“一对一”的线程模型,即一个LWP对应一个线程。这个模型最大的好处是线程调度由内核完成了,而其他线程操作(同步、取消)等都是核外的线程库函数完成的。
linux上的线程就是基于轻量级进程,
对此, POSIX标准提出了如下要求:
1,
2,
3,
4,
5,
6,
在LinuxThreads中,专门为每一个进程构造了一个管理线程,负责处理线程相关的管理工作。当进程第一次调用pthread_create()创建一个线程的时候就会创建并启动管理线程。然后管理线程再来创建用户请求的线程。也就是说,用户在调用pthread_create后,先是创建了管理线程,再由管理线程创建了用户的线程。
linuxthreads利用前面提到的轻量级进程来实现线程,
1,
2,
3, SIGSTOP/SIGCONT信号只对一个线程起作用;
还好linuxthreads实现了第5点,
但是, linuxthreads为了实现这个"第5点",
接下来要说说,
当程序开始运行时,
程序第一次调用pthread_create时, linuxthreads发现管理线程不存在,
然后在pthread_create中,
于是,
那么,
可见,
创建与销毁需要一次进程间通信,
这种通过LWP的方式来模拟线程的实现看起来还是比较巧妙的,但也存在一些比较严重的问题:
1)线程ID和进程ID的问题
按照POSIX的定义,同一进程的所有的线程应该共享同一个进程和父进程ID,而Linux的这种LWP方式显然不能满足这一点。
2)信号处理问题
异步信号是以进程为单位分发的,而Linux的线程本质上每个都是一个进程,且没有进程组的概念,所以某些缺省信号难以做到对所有线程有效,例如SIGSTOP和SIGCONT,就无法将整个进程挂起,而只能将某个线程挂起。
3)线程总数问题
LinuxThreads将每个进程的线程最大数目定义为1024,但实际上这个数值还受到整个系统的总进程数限制,这又是由于线程其实是核心进程。
4)管理线程问题
管理线程容易成为瓶颈,这是这种结构的通病;同时,管理线程又负责用户线程的清理工作,因此,尽管管理线程已经屏蔽了大部分的信号,但一旦管理线程死亡,用户线程就不得不手工清理了,而且用户线程并不知道管理线程的状态,之后的线程创建等请求将无人处理。
5)同步问题
LinuxThreads中的线程同步很大程度上是建立在信号基础上的,这种通过内核复杂的信号处理机制的同步方式,效率一直是个问题。
6)其他POSIX兼容性问题
Linux中很多系统调用,按照语义都是与进程相关的,比如nice、setuid、setrlimit等,在目前的LinuxThreads中,这些调用都仅仅影响调用者线程。
7)实时性问题
线程的引入有一定的实时性考虑,但LinuxThreads暂时不支持,比如调度选项,目前还没有实现。不仅LinuxThreads如此,标准的Linux在实时性上考虑都很少
模型二:NPTL
到了linux 2.6, glibc中有了一种新的pthread线程库--NPTL(Native POSIX Threading Library).
本质上来说,NPTL还是一个LWP的实现机制,但相对原有LinuxThreads来说,做了很多的改进。下面我们看一下NPTL如何解决原有LinuxThreads实现机制的缺陷
NPTL实现了前面提到的POSIX的全部5点要求.
在linux 2.6中,
如果这个task是一个"主线程",
在clone系统调用中,
类似的XXid在task_struct中还有两
有了tgid,
而getpid(获取进程ID)系统调用返回的也是tast_struct中的tgid,
在执行ps命令的时候不展现子线程,也是有一些问题的。比如程序a.out运行时,创建
为了应付"发送给进程的信号"和"发送给线程的信号", task_struct里面维护了两套signal_pending,
通过kill发送的信号被放在线程组共享的signal_pending中,
当线程停止/继续,
NGPT
上面提到的两种线程库使用的都是内核级线程(每个线程都对应内核中的一个调度实体),
而NGPT则打算实现M:N模型(M个线程对应N个内核级线程),
线程库需要在一个内核提供的执行实体上抽象出若干个执行实体,
大体上,
但是实际上要处理的细节问题非常之多.
用户级线程的切换显然要比内核级线程的切换快一些,
而用户级线程则不能享受多处理器,
不过, M:N的线程模型毕竟提供了这样一种手段,
Linux的另一种可选线程模型是IBM开发的NGPT(Next Generation Posix Threads for Linux),它是基于GNU Pth(GNU Portable Threads)项目而实现的M:N模型(M个用户态线程对应N个核心态线程)。
Linux Implementations of POSIX Threads——POSIX线程的Linux版实现
Next Generation POSIX Threads (NGPT)
基于M:N模型的linux线程库,由IBM开发。性能介于LinuxThreads和NPTL,03年终止开发了~~
Linux Threads
Linux的一代功臣,2.6之前的kernel使用的线程库,由Xavier Leroy开发的~~大致的实现过程是:通过clone系统调用,参数CLONE_VM | CLONE_FILES | CLONE_FS | CLONE_SIGHAND 分别用来指明共享创建者的VM虚拟内存(用户空间)、文件描述符、文件系统相关属性(umask,root directory等)、信号处理程序表和阻塞信号表和挂起信号表。kernel创建一个Manager Thread管理所有线程创建与结束等。实现内部使用real-time 实时Singal用来传递操作信息。另外,Linux Threads 与标准差异参见TLPI-33.5.1,这也是它被NPTL取代的原因。
NPTL (Native POSIX Threads Library)
Kernel2.6沿用至今,Linux Threads的继承者,有Ulrich Drepper
Linux进程和线程的发展
1999年1月发布的Linux 2.2内核中,进程是通过系统调用fork创建的,新的进程是原来进程的子进程。需要说明的是,在2.2.x版本中,不存在真正意义上的线程(thread)。Linux中常用的线程Pthread实际上是通过进程来模拟的。也就是说Linux中的线程也是通过fork创建的,是“轻”进程。Linux 2.2只默认允许4096个进程/线程同时运行。高端系统同时要服务上千个用户,所以这显然是一个问题,它一度是阻碍Linux进入企业级市场的一大因素。
2001年1月发布的Linux 2.4内核消除了这个限制,并且允许在系统运行中动态调整进程数上限。因此,进程数现在只受制于物理内存的多少。在高端服务器上,即使安装了512MB内存,现在也能轻而易举地同时支持1万6千个进程。
2003年12月发布的2.6内核,进程调度经过重新编写,去掉了以前版本中效率不高的算法。以前,为了决定下一步要运行哪一个任务,进程调度程序要查看每一个准备好的任务,并且经过计算机来决定哪一个任务相对来更为重要。进程标识号(PID)的数目也从32000升到10亿。内核内部的大改变之一就是Linux的线程框架被重写,以使NPTL(Native POSIX Thread Library)可以运行于其上。对于运行负荷繁重的线程应用的Pentium Pro及更先进的处理器而言,这是一个主要的性能提升,也是企业级应用中的很多高端系统一直以来所期待的。线程框架的改变包含Linux线程空间中的许多新的概念,包括线程组、线程各自的本地存储区、POSIX风格信号,以及其他改变。改进后的多线程和内存管理技术有助于更好地运行大型多媒体应用软件。这个线程库有以下几个目标: POSIX兼容,都处理结果和应用,底启动开销,低链接开销,与Linux Thread应用的二进制兼容,软硬件的可扩展能力,与C++集成等。 这一切是2.6的内核多线程机制更加完备。