因为历史缘由,2.5.x之前的linux对pthreads没有提供内核级的支持,因此在linux上的pthreads实现只能采用n:1的方式,也称为库实现。html
线程的实现,经历了以下发展阶段:linux
目前,pthreads的实现有3种方式:算法
(1)第一种,多对一,linux Threads,也就是库实现。shell
linux Threads,这是linux标准的的线程库,可是与IEEE的POSIX不兼容. 在LinuxThreads中,专门为每个进程构造了一个管理线程,负责处理线程相关的管理工做。当进程第一次调用pthread_create()建立一个线程的时候就会建立并启动管理线程。而后管理线程再来建立用户请求的线程。也就是说,用户在调用pthread_create后,先是建立了管理线程,再由管理线程建立了用户的线程。编程
(2)第二种,1:1模式。 NPTL多线程
1:1模式适合CPU密集型的机器。咱们知道,进程(线程)在运行中会因为等待某种资源而阻塞,多是I/O资源,也多是CPU。在多CPU机器上1:1模式是个很不错的选择。所以1:1的优势就是,可以充分发挥SMP的优点。
这种模式也有它的缺点。因为OS为每一个线程创建一个内核线程,致使内核级的内存空间(IA32机器的4G虚存空间的最高1G)的大开销。第二个缺点在于,在传统意义上,在mutex互斥锁和条件变量上的操做要求进入内核态,这是由于OS负责调度,它要为线程的转态转换负全责。后面咱们会看到,Linux的NPTL库避免了这个缺点,它的互斥锁与条件变量的操做在用户态完成。post
(3)第三种,M:N模式。测试
这种模式试图兼有上面2种模式的优势。它要求一个分层的模型。比方说,某个进程内有4个线程,其中每2个线程对应一个内核线程。这样,OS知道2个实体的存在,负责它们的调度。而在一个实体内有2个线程,这2个线程间的调度就是OS不加干涉、也不知道的了。
简单的说,M:N模型的OS级调度上,跟1:1模型类似;线程间调度上,跟n:1模型类似。
优势是,既能够在进程内利用SMP的优点,又能够节省系统空间内存的消耗,并且环境切换大多在用户态完成。
缺点是显然的:复杂。spa
Linux线程是经过进程来实现。Linux kernel为进程建立提供一个clone()系统调用,clone的参数包括如 CLONE_VM, CLONE_FILES, CLONE_SIGHAND 等。经过clone()的参数,新建立的进程,也称为LWP(Lightweight process)与父进程共享内存空间,文件句柄,信号处理等,从而达到建立线程相同的目的。操作系统
普通进程和LWP在实现上的不一样点是:
线程和LWP是同一个东西,只是在用户态,咱们管进程中每个执行序列为“线程”,可是内核中它被称为LWP。由于内核上没有线程的概念,CPU的调度是以进程为单位的。
在Linux 2.6以前,Linux kernel并无真正的thread支持,一些thread library都是在clone()基础上的一些基于user space的封装,所以一般在信号处理、进程调度(每一个进程须要一个额外的调度线程)及多线程之间同步共享资源等方面存在必定问题。Linux 2.6的线程库叫NPTL(Native POSIX Thread Library)。POSIX thread(pthread)是一个编程规范,经过此规范开发的多线程程序具备良好的跨平台特性。尽管是基于进程的实现,但新版的NPTL建立线程的效率很是高。一些测试显示,基于NPTL的内核建立10万个线程只须要2秒,而没有NPTL支持的内核则须要长达15分钟。
在Linux中,每个线程都有一个task_struct。线程和进程可使用同一调度其调度。内核角度上来将LWP和Process没有区别,有的仅仅是资源的共享。若是独享资源则是HWP,共享资源则是LWP。而在真正内核实现的NPTL的实现是在kernel增长了futex(fast userspace mutex)支持用于处理线程之间的sleep与wake。futex是一种高效的对共享资源互斥访问的算法。kernel在里面起仲裁做用,但一般都由进程自行完成。NPTL是一个1×1的线程模型,即一个线程对于一个操做系统的调度进程,优势是很是简单。而其余一些操做系统好比Solaris则是MxN的,M对应建立的线程数,N对应操做系统能够运行的实体。(N<M),优势是线程切换快,但实现稍复杂。
注:
(1)pthread线程库--NPTL(Native POSIX Threading Library)
在1:1核心线程模型中,应用程序建立的每个线程(也有书称为LWP)都由一个核心线程直接管理。OS内核将每个核心线程都调到系统CPU上,
所以,全部线程都工做在“系统竞争范围”(system contention scope):线程直接和“系统范围”内的其余线程竞争。
(2)NGPT(Next Generation POSIX Threads)
N:M混合线程模型提供了两级控制,将用户线程映射为系统的可调度体以实现并行,这个可调度体称为轻量级进程(LWP:light weight process),LWP
再一一映射到核心线程。以下图所示。OS内核将每个核心线程都调到系统CPU上,所以,全部线程都工做在“系统竞争范围”。
添加:各阶段线程的具体实现
在LinuxThreads中,专门为每个进程构造了一个管理线程,负责处理线程相关的管理工做。当进程第一次调用pthread_create()建立一个线程的时候就会建立并启动管理线程。而后管理线程再来建立用户请求的线程。也就是说,用户在调用pthread_create后,先是建立了管理线程,再由管理线程建立了用户的线程。
为了遵循POSIX对线程的一个规定:当"进程"收到一个致命信号(好比因为段错误收到SIGSEGV信号), 进程内的线程所有退出
,LinuxThreads的实现方法:
容易发现,管理线程可能成为多线程系统的瓶颈,线程建立和销毁的开销很大(须要IPC)。
更为重要的是,LinuxThreads没法知足Posix对线程的绝大多数规定,好比:
在linux 2.6中, 内核有了线程组的概念, task_struct结构中增长了一个tgid(thread group id)字段.
若是这个task是一个"主线程", 则它的tgid等于pid, 不然tgid等于进程的pid(即主线程的pid).
经过以下方式,解决了LinuxThreads不能兼容POSIX的问题:
上面提到的两种线程库使用的都是内核级线程(每一个线程都对应内核中的一个调度实体), 这种模型称为1:1模型(1个线程对应1个内核级线程);
而NGPT则打算实现M:N模型(M个线程对应N个内核级线程), 也就是说若干个线程多是在同一个执行实体上实现的.
由于模型太复杂,貌似没有实现出来全部预约功能,因此被放弃了。
参考连接
Linux进程、线程模型,LWP,pthread_self() http://blog.csdn.net/tianyue168/article/details/7403693