什么是线程?线程和进程是什么关系?这是一个很抽象的问题,也是一个很宽泛的话题,涉及到很多知识。我不能确定我能说出它说的,我也不能确定我说的都是正确的。尽管如此,我还是希望尽可能简单明了,因为这是一个困扰我很久的扑朔迷离的知识领域,我希望通过自己的理解来揭开它的层层谜团。什么是任务调度线程?要理解这个概念,需要先了解操作系统的一些相关概念。大部分操作系统(如Windows、Linux)的任务调度都采用时间片轮换的抢占式调度方式,即一个任务强制暂停一小段时间后执行下一个任务,而每个任务依次执行。任务执行的一小段时间称为时间片,任务执行时的状态称为运行状态。一段时间后,任务强制挂起执行下一个任务。挂起的任务处于就绪状态,等待属于它的下一个时间片。到达。这样每一个任务都可以执行。由于CPU的执行效率很高,时间片很短,在各种任务之间快速切换给人的感觉是多个任务“同时进行”,这就是我们所说的并发(don'想想并发有多高级,它的实现很复杂,但它的概念很简单,就一句话:多个任务同时执行)。多任务运行过程示意图如下:图1:操作系统中的任务调度我们都知道计算机的核心是CPU,它承担着所有的计算任务;操作系统是计算机的管理者,负责任务调度和资源分配。计算机的分布和管理控制着整个计算机硬件;应用端是具有一定功能的程序,程序运行在操作系统之上。进程是在数据集上动态执行具有某些独立功能的程序的过程。它是操作系统进行资源分配和调度的独立单位,是应用程序运行的载体。进程是一个抽象的概念,从来没有一个统一的标准定义。一个进程一般由三部分组成:程序、数据采集和进程控制块。程序用于描述进程要完成的功能,是控制进程执行的指令集;数据集是程序在执行过程中需要的数据和工作区;程序控制块(ProgramControlBlock,简称PCB),包含了进程的描述信息和控制信息,是进程存在的唯一标志。进程的特点:动态性:进程是程序的一个执行过程,是临时的,有生命周期,动态生成,动态消亡;并发性:任何进程都可以与其他进程并发执行;独立性:进程是系统进行资源分配和调度的独立单元;结构:一个进程由三部分组成:程序、数据和进程控制块。在早期的操作系统中,没有线程的概念。进程是能够拥有资源并独立运行的最小单位,也是程序执行的最小单位。任务调度采用时间片轮换的抢占式调度方式,进程是任务调度的最小单位。每个进程都有自己独立的一块内存,这样每个进程的内存地址都是相互隔离的。后来随着计算机的发展,对CPU的要求越来越高,进程之间的切换开销也比较大,已经不能满足越来越复杂的程序的要求。于是发明了线程。线程是程序执行中单一的顺序控制流,是程序执行流的最小单位,是处理器调度调度的基本单位。一个进程可以有一个或多个线程,每个线程共享程序的内存空间(即进程的内存空间)。标准线程由线程ID、当前指令指针(PC)、寄存器和堆栈组成。而进程由内存空间(代码、数据、进程空间、打开的文件)和一个或多个线程组成。进程和线程的区别前面讲了进程和线程,大家可能还是一头雾水,觉得它们很相似。的确,进程和线程有着千丝万缕的联系,我们一起来看看:线程是程序执行的最小单位,进程是操作系统分配资源的最小单位;一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路径;进程之间是相互独立的,但同一个进程下的各个线程共享程序的内存空间(包括代码段、数据集、堆等)和一些进程级的资源(比如打开的文件和信号),线程在一个进程中对其他进程不可见;调度和切换:线程上下文切换比进程上下文切换快得多。线程与进程的关系示意图:图2:进程与线程的资源共享关系图3:单线程与多线程的关系总之,线程和进程都是抽象概念,线程是一种更小的抽象processes,线程和进程都可以用来实现并发。在早期的操作系统中,没有线程的概念。进程是能够拥有资源并独立运行的最小单位,也是程序执行的最小单位。相当于一个进程中只有一个线程,进程本身就是一个线程。所以线程有时也被称为轻量级进程(LightweightProcess,LWP)。图4:早期的操作系统只有进程而没有线程。后来随着计算机的发展,多个任务之间上下文切换的效率越来越高,抽象出一个更小的概念——线程,一般一个进程会有多个(或一个)线程。图5:线程的出现使得一个进程可以拥有多个线程。多线程和多核。上面提到的时间片轮换调度方式,是指一个任务在短时间后强制暂停执行下一个任务,每个任务轮流执行。.许多操作系统书籍都说“同一时间只有一个任务在执行”。那么有人可能会问双核处理器呢?两个核心不是同时运行吗?其实,“只有一个任务在同时执行”这句话是不准确的,至少是不全面的。在多核处理器的情况下,线程如何执行?这需要了解内核线程。多核(core)处理器是指在一个处理器上集成了多个计算核心来提高计算能力,即有多个处理核心进行真正的并行计算,每个处理核心对应一个内核线程。内核线程(KernelThread,KLT)是操作系统内核直接支持的线程。这种线程由内核切换。内核通过操作调度器对线程进行调度,负责将线??程的任务映射到各个处理器上。.通常,一个处理核心对应一个内核线程,例如单核处理器对应一个内核线程,双核处理器对应两个内核线程,四核处理器对应四个内核线程。现在的电脑一般都是双核四线程,四核八线程,超线程技术就是把一个物理处理核心模拟成两个逻辑处理核心,对应两个内核线程,所以看到的CPU数量操作系统是实际的数字。物理CPU数量的两倍,如果你的电脑是双核四线程,打开“任务管理器\性能”可以看到4个CPU显示器,四核八线程可以看到8个CPU显示器。图6:Windows8下双核四线程查看结果超线程技术是利用特殊的硬件指令将一个物理芯片模拟成两个逻辑处理核心,从而使单个处理器可以使用线程级并行计算,以及然后兼容多线程操作系统和软件,减少CPU的空闲时间,提高CPU的运行效率。这种超线程技术(如双核四线程)是由处理器硬件决定的,也需要操作系统的支持才能在电脑中显示出来。程序一般不直接使用内核线程,而是使用内核线程的一个高层接口——轻量进程(LightWeightProcess,LWP)。轻量进程就是我们通常所说的线程(我们这里称之为用户线程),由于每个轻量进程都有一个内核线程支持,只有先支持内核线程才能有轻量进程。用户线程和内核线程的对应关系有三种模型:一对一模型、多对一模型和多对多模型。这里以4个内核线程和3个用户线程为例,对三种模型进行说明。一对一模型对于一对一模型,一个用户线程唯一对应一个内核线程(反之则不一定,一个内核线程也不一定对应一个用户线程)。这样,如果CPU没有使用超线程技术(比如四核四线程的计算机),一个用户线程就唯一映射到物理CPU的一个线程,线程之间的并发才是真正的并发。一对一模型使用户线程具有与内核线程相同的优势。当一个线程由于某种原因阻塞时,其他线程的执行不受影响;在这里,一对一模型还可以让多线程程序在多处理器系统上运行时获得更好的性能。但是一对一模型也有两个缺点:1.很多操作系统限制了内核线程数,所以一对一模型会限制用户线程数;2.许多操作系统在调度内核线程时上下文切换的开销较大,导致用户线程的执行效率下降。图7:一对一模型多对一模型多对一模型将多个用户线程映射到一个内核线程,线程之间的切换由用户态代码执行。因此,相对于一对一模型,多对一模型的线程切换速度要快很多;此外,多对一模型几乎对用户线程数有限制。但是多对一模型也有两个缺点:1、如果其中一个用户线程被阻塞,其他所有线程都将无法执行,因为此时内核线程也被阻塞了;增加数量不会显着提高多对一模型的线程性能,因为所有用户线程都映射到一个处理器。图8:多对一模型多对多模型结合了一对一模型和多对一模型的优点,将多个用户线程映射到多个内核线程。多对多模型的优点是:1、一个用户线程阻塞不会导致所有线程阻塞,因为此时还有其他内核线程调度执行;2.多对多模型对用户线程数没有限制;3.在多处理器操作系统中,多对多模型的线程也可以获得一定的性能提升,但提升幅度没有一对一模型高。在目前流行的操作系统中,大多采用多对多的模型。图9:多对多模型查看进程和线程一个应用程序可能是多线程的,也可能是多进程的,如何查看呢?在Windows下,我们只需要打开任务管理器就可以查看一个应用程序Threads的进程和进程。按“Ctrl+Alt+Del”或右击快捷工具栏打开任务管理器。查看进程数和线程数:图10:查看线程数和进程数在“进程”选项卡下,我们可以看到一个应用程序包含的线程数。如果一个应用程序有多个进程,我们可以看到每个进程。比如上图,谷歌的chrome浏览器有多个进程。同时,如果打开一个应用程序的多个实例,也会有多个进程。如上图,如果我打开两个cmd窗口,就会有两个cmd进程。如果看不到threadcount栏,可以点击“View\SelectColumn”菜单添加监控栏。查看CPU和内存使用率:在性能选项卡中,我们可以查看CPU和内存使用率,根据CPU使用率记录的监视器数量也可以看到逻辑处理核心数,比如我的双核四核线程计算机有四个显示器。图11:查看线程的CPU和内存使用生命周期当线程数小于处理器数时,线程的并发为真并发,不同的线程运行在不同的处理器上。但是当线程数大于处理器数时,线程的并发性就会受到阻碍。这时候就不是真正的并发,因为此时至少有一个处理器会运行多个线程。并发是单个处理器运行多个线程时的模拟状态。操作系统采用时间片轮换的方式轮流执行各个线程。现在,几乎所有现代操作系统都采用时间片循环抢占式调度,比如我们熟悉的Unix、Linux、Windows、MacOSX等流行操作系统。我们知道线程是程序执行的最小单位,也是任务执行的最小单位。在早期只有进程的操作系统中,进程有五种状态,创建、就绪、运行、阻塞(等待)、退出。早期进程相当于当前进程只有一个线程,所以当前多线程也有五个状态,当前多线程的生命周期与早期进程的生命周期类似。图12:一个早期进程的生命周期一个进程的运行过程有三种状态:就绪、运行、阻塞,创建和退出状态描述了进程的创建过程和退出过程。CREATE:进程正在创建中,还不能运行。操作系统在创建进程时要做的工作包括分配和建立进程控制块表项、建立资源表和分配资源、加载程序和建立地址空间;ready:时间片已经用完,本线程被强制挂起,等待下一个属于他的时间片到来;running:该线程正在执行,正在占用时间片;阻塞:也叫等待状态,等待一个事件(比如IO或者另一个线程)被执行;exit:进程已经结束,所以也称为结束状态,操作系统分配的资源被释放。图13:线程生命周期创建:创建一个新的线程,等待线程被调用执行;ready:时间片已用完,本线程被迫挂起,等待下一个属于它的时间片;running:该线程正在执行,正在占用一个时间片;阻塞:也叫等待状态,等待一个事件(比如IO或者另一个线程)被执行;exiting:当一个线程完成一个任务或其他终止条件出现时,该线程终止并进入退出状态。退出状态释放线程分配的资源。
