Linux线程技术的概念与技术发展
Linux是一个多用户、多任务的操作系统。多用户是指多个用户可以在同一时间使用计算机系统;多任务是指Linux可以同时执行几个任务,它可以在还未执行完一个任务时又执行另一项任务。在操作系统设计上,从进程(Process)演化出线程(Thread),最主要的目的就是更好地支持多处理器,并且减小(进程/线程)上下文切换的开销。
进程和线程的关系
根据操作系统的定义,进程是系统资源管理的最小单位,线程是程序执行的最小单位。线程和进程十分相似,不同的只是线程比进程小。
首先,线程采用了多个线程可共享资源的设计思想。例如,它们的操作大部分都是在同一地址空间进行的。其次,从一个线程切换到另一线程所花费的代价比进程低。再次,进程本身的信息在内存中占用的空间比线程大。
因此,线程更能允分地利用内存。线程可以看作是在进程内部执行的指定序列。线程和进程的最大区别在于线程完全共享相同的地址空间,运行在同一地址上。
Linux线程的定义
线程是在共享内存空间中并发的多道执行路径,它们共享一个进程的资源,如文件描述和信号处理。在两个普通进程(非线程)间进行切换时,内核准备从一个进程的上下文切换到另一个进程的上下文要花费很大的开销。
这里上下文切换的主要任务是保存老进程CPU状态,并加载新进程的保存状态,用新进程的内存映像替换老进程的内存映像。线程允许进程在几个正在运行的任务之间进行切换,而不必执行前面提到的完整的上下文。
在Unix类系统中,曾经出现过一些不同线程标准,它们都支持可移植操作系统接口标准POSIX(Portable Operating System Interface Standard)。
POSIX标准由IEEE制定,并由国际标准化组织接受为国际标准。POSIX 1003.1c是一个用于线程(在一个程序中当前被执行的代码段)的标准,以前是P1993.4或POSIX.4的一部分,这个标准已经在1995年被IEEE通过,归入ISO/IEC 9945-1:1996。
本文介绍线程主要是针对POSIX线程,即Pthread,因为Linux对它的支持最好。相对进程而言,线程是一个更加接近于执行体的概念,它可以与进程中的其它线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。在串行程序基础上引入线程和进程是为了提高程序的并发度,从而提高程序运行效率和响应时间。
也可以将线程和轻量级进程(LWP)视为等同,但其实在不同的系统/实现中有不同的解释。LWP更恰当的解释可能为一个虚拟CPU或内核的线程,它可以帮助用户态线程实现一些特殊的功能。Pthread是一种标准化模型,它用来把一个程序分成一组能够同时执行的任务。
那么在什么场合会使用Pthread呢?
◆在返回前阻塞的I/O任务能够使用一个线程处理,同时继续执行其它处理任务。
◆在有一个或多个任务受不确定性事件影响,比如网络通信的可获得性影响的场合,能够使用线程处理这些异步事件,同时继续执行正常的处理。
◆如果某些程序功能比其它的功能更重要,可以使用线程以保证所有功能都出现,但那些时间密集型的功能具有更高的优先级。
以上三点可以归纳为在检查程序中潜在的并行性时,也就是说找出能够同时执行任务时使用Pthread。上面介绍了Linux进程模型已经提供了执行多个进程的能力,可以进行并行或并发编程,但是,线程对多个任务的控制程度要更好,使用资源更少。因为一个单一的资源,如全局变量,可以由多个线程共享,而且,在拥有多个处理器的系统上多线程应用会由用多个进程实现的应用执行。
Linux进程和线程技术发展
线程技术早在20世纪60年代就被提出,但真正应用多线程到操作系统中还是在20世纪80年代中期。现在,多线程技术已经被许多操作系统所支持,包括Windows NT/2000和Linux。
在1999年1月发布的Linux 2.2内核中,进程是通过系统调用fork创建的,新的进程是原来进程的子进程。需要说明的是,在Linux 2.2.x中,不存在真正意义上的线程,Linux中常用的线程Pthread实际上是通过进程来模拟的。
也就是说,Linux中的线程也是通过fork创建的,是“轻”进程。Linux 2.2缺省只允许4096个进程/线程同时运行,而高端系统同时要服务上千的用户,所以这显然是一个问题。它一度是阻碍Linux进入企业级市场的一大因素。
2001年1月发布的Linux 2.4内核消除了这个限制,并且允许在系统运行中动态调整进程数上限。因此,进程数现在只受制于物理内存的多少。在高端服务器上,即使只安装了512MB内存,现在也能轻而易举地同时支持1.6万个进程。
在Linux 2.5内核中,已经做了很多改进线程性能的工作。在Linux 2.6中改进的线程模型仍然是由Ingo Molnar 来完成的。它基于一个1:1的线程模型(一个内核线程对应一个用户线程),包括内核内在的对新NPTL(Native Posix Threading Library)的支持,这个新的NPTL是由Molnar和Ulrich Drepper合作开发的。
2003年12月发布的Linux 2.6内核,对进程调度经过重新编写,去掉了以前版本中效率不高的算法。进程标识号(PID)的数目也从3.2万升到10亿。内核内部的大改变之一就是Linux的线程框架被重写,以使NPTL可以运行其上。
Linux的另一种可选线程模型是IBM开发的NGPT(Next Generation Posix Threads for Linux),它是基于GNU Pth(GNU Portable Threads)项目而实现的M:N模型(M个用户态线程对应N个核心态线程)。
NPTL的设计目标可归纳为以下几点:POSIX兼容性、SMP结构的利用、低启动开销、低链接开销(即不使用线程的程序不应当受线程库的影响)、与LinuxThreads应用的二进制兼容性、软硬件的可扩展能力、多体系结构支持、NUMA支持,以及与C++集成等。
对于运行负荷繁重的线程应用Pentium Pro及更先进的处理器而言,这些是主要的性能提升,也是企业级应用中很多高端系统一直以来所期待的。线程框架的改变包含Linux线程空间中的许多新的概念,包括线程组、线程各自的本地存储区、POSIX风格信号,以及其它改变。改进后的多线程和内存管理技术有助于更好地运行大型多媒体应用软件。Linux线程实现方法
目前线程有用户态线程和核心态线程两种方法实现。
1.用户态线程
用户态线程是一个精细的软件工具,允许多线程的程序运行时不需要特定的内核支持。如果一个进程中的某一个线程调用了一个阻塞的系统调用,则该进程就会被阻塞,该进程中的其它所有线程也同时被阻塞。因此,Unix使用了异步I/O机制。这种机制主要的缺点在于,在一个进程中的多个线程调度中无法发挥多处理器的优势(如上述的阻塞情况)。
用户态线程优点如下:
◆某些线程操作的系统消耗大大减少。比如,对属于同一个进程的线程之间进行调度切换时,不需要调用系统调用,因此将减少额外的消耗,一个进程往往可以启动上千个线程。
◆用户态线程的实现方式可以被定制或修改,以适应特殊应用的要求。它对于多媒体实时过程等尤其有用。另外,用户态线程可以比核心态线程实现方法默认情况支持更多的线程。
2.核心态线程
核心态线程的实现方法允许不同进程中的线程按照同一相对优先调度方法进行调度,这样有利于发挥多处理器的并发优势。
目前,线程主要的实现方法是用户态线程。有几个研究项目已经实现了一些核心态线程的形式,其中比较著名的是MACH分布式操作系统。
通过允许用户代码对内核线程调度的参与,该系统将用户态和核心态两种线程实现方法的优点结合了起来。通过提供这样一个两级调度机制,内核在保留了对处理器时间分配控制的同时,也使一个进程可以充分利用多处理器的优势。
Linux对超线程技术支持
超线程技术(Hyperthreading Technology)是Intel公司的创新设计。HT技术就是利用特殊的硬件指令,把两个逻辑内核模拟成两个物理芯片,让单个处理器都能使用线程级并行计算,从而兼容多线程操作系统和软件,并提高处理器的性能。
操作系统或应用软件的多线程可以同时运行于一个处理器上,两个逻辑处理器共享一组处理器执行单元,并行完成加、乘、负载等操作。在同一时间里,应用程序可以使用芯片的不同部分。虽然单线程芯片每秒钟能够处理成千上万条指令,但是在任一时刻只能够对一条指令进行操作。
而HT技术可以使芯片同时进行多线程处理,当在支持多处理器的Windows XP或Linux等操作系统之下运行时,同时运行多个不同的软件程序可以获得更高的运行效率。这两种方式都可使计算机用户获得更优异的性能和更短的等待时间。Linux是第一个把超线程特性引入市场的操作系统,它在发布2.4.17内核时,就开始包含对Intel P4处理器的超线程的支持(Linux 2.4内核最初的发布版本中不支持),它包括以下增强技术:
◆128字节锁对齐。
◆螺旋等待循环优化。
◆基于非执行的延迟循环 。
◆检测支持超线程的处理器,并启动逻辑处理器,如同该机器是SMP(多处理器构架)。
◆MTRR和微码更新(Microcode Update)驱动程序中的串行化,因为它们影响共享状态。
◆在逻辑处理器调度发生之前,当系统空闲时对物理处理器上的调度进行优先级排序时,对调度程序进行优化。
◆偏移用户堆栈以避免64K混叠。
以上简单介绍了Linux线程的属性、与进程关系、线程的实现方法,以及Linux对超线程技术支持等,希望对大家了解Linux线程技术有所帮助。