"泥土里的蚂蚁哪儿能搞懂,天边的海鸥?"
我们翻开任意一本讲操作系统的书籍,对于进程的描述,一个最经典的定义是:一个"执行中的实例"。那么什么是线程呢?一本书给的定义是:"线程是进程中的一个实体,是被系统独立调用和运行的基本单位。",另一本书给的定义是:"运行在进程上下文中的逻辑流。"从书本上给的定义来看,唔,我们的猜测是线程相比于进程而言更小,甚至是线程是进程的一个部分。
此时你也许会说,你说的这些我都不知道,是的,这些概念就是抽象的代名词,太过于宏观了。那么我们又该如何在Linux进程管理的基础上理解线程这个概念呢?
---前言
也许单独问你,进程是什么时,你可能支支吾吾不知道如何作答。但如果你对进程创建了解过,那么换个方式问你,进程创建时,或者说双击.exe文件时会发生什么?
是的OS会为我们创建一个task_struct 也就是PCB(进程控制块)。并且会为该进程开辟一份独立的虚拟地址空间,创建一份唯一性页表,并与物理内存建立映射。
我们之前的进程 = 内核数据结构 + 进程相应的代码与数据
虚拟地址空间和页表的本质,就是对系统资源的划分,决定了该进程可以看到的系统资源范围。
由此,站在内核角度该如何看待进程呢?
承担系统分配资源的基本实体
操作系统的管理离不开一个"六字真言":"先描述,后组织"。如果我们需要创建一个线程,我们应该为该线程创建一个结构体,用于维护线程创建的属性信息,并且OS中不止有一个线程,它一定存在众多线程,emmm....看来我们也得为线程之间维护一定关系,方便对多个线程进行管理。
线程控制块(Thread Control Block,TCB)是与进程的控制块(PCB)相似的子控制块,只是TCB中所保存的线程状态比PCB中保存少而已。 取自这里
为此,你要创建线程那么一定得为线程设计一个款专门的数据结构对象(比如:Windows系统就有一套专门的内核级数据结构),其中一定得包括线程如何被调度,以及其状态、优先级、上下文、栈……这像什么???这难道不就是Linux系统下对一个进程管理时,所用到的方式嘛?
单纯从线程调用的角度来看,进程和线程很多地方都是重叠的!因此,Linux工程师选择不单独地为显"线程"设计数据结构,而是直接复用PCB!在Linux内部PCB就表示"线程"。
这容易实现嘛?当然!
线程是在进程内部运行,是在进程地址空间内运行,享有进程的一部分资源。
是进程内部中的一个"执行流"。
在Linux中,线程是CPU调度的基本单位。
我们也就能够很具象化地理解为什么说,线程是一个进程下的"执行流"。这样的概念。
因此,Linux下根本无所谓"线程",它是由进程的PCB控制块来模拟线程,是一种完全属于自己的方案。
其次,站在CPU的视角下,它只关心task_struct,而我们现在的 task_struct <= (进程PCB),它的概念范围更小。也常常叫做,"轻量级进程"。
我们之前创建的进程,只有单个执行流而已。一个进程可以有多个执行流。
在Linux下CPU调度"线程"与CPU调度进程的开销,并不仅仅在于"线程"不需要建立新的虚拟地址空间、建立新的页表与新的映射,不需要切换PCB && 切换上下文数据……
当进行线程切换时,cache不需要做什么太大的更新。因为都是同一个进程里的上下文热点数据。但如果是发生进程切换,那么cahce内需要更新的数据就更大了。
①进程是承担资源分配的实体,线程是CPU调度的基本单位。
②Linux当中不存在"线程"概念,它的执行流是一种轻量级进程。