首先,我们引入一些基本的概念,并结合我们以前所学过的知识,初步对这些概念有个大体的理解
1.线程是一个执行分支,执行粒度比进程更细,调度成本更低
2.线程是进程内部的一个执行流
3.线程是CPU调度的基本单位,进程是承担分配系统资源的基本实体
怎么理解这些概念呢?线程又和我们当初所学的进程有什么区别呢?
我们先来看一下,我们之前是怎么理解进程的?
我们执行一段代码,对应的就是一个进程被创建,每个进程有着自己对应的虚拟地址空间(4GB),然后通过页表,将相应的代码和数据,映射到对应的物理内存之中
当然每个进程还会创建相应的PCB,在linux系统下,为task_struct结构体进行管理进程
如果有多个进程,其实只是复制上面的流程,原模原样的拷贝,一点都没有变化,创建一个子进程也是如此,最多发生写时拷贝,让各自的数据私有化,但都会有各自的PCB,也就是task_struct
但是假如现在情况变了呢?
有多个task_struct指向同一个虚拟地址空间,这些task_struct没有自己单独的虚拟地址空间
有了这样的结构,正文代码假如存在多个函数,就可以将任务分派出去,让每个task_struct分别负责不同的函数,由原来的串发执行,变为并发执行
我们就把这几个task_struct称之为一个单独的线程
现在我们就可以理解上面所说的概念了
执行粒度比进程更细:
因为每个pcb负责的只是当初任务的一小部分,而进程则是一整个大任务,所以自然粒度更细
线程是进程内部的一个执行流(执行分支)
一个线程在进程的地址空间内运行,该线程是隶属于进程的
调度成本更低
1.当CPU执行OS的代码时,会检测对应的PCB,然后发现对应的虚拟地址空间等等都是完全相同的,那就不再需要切换相应的地址空间和页表,那自然成本更低
2.CPU内部存在硬件cache l1,l2,l3,该硬件的功能就是提前将部分热点数据和代码保存起来(预加载),这样就不用直接从物理内存中加载,CPU从cache中获取对应的代码即可
而有了线程,不用再对cache进行切换
那我们如何看待task_struct呢?毕竟我们之前一直把它看作是一个进程的标志,一个进程,必定对应一个task_struct
答案是PCB既不是线程也不是进程,而是一个执行流
而一个进程包括所有一大堆的东西,每个进程有自己的CPU资源,有自己的地址空间,有自己的页表等等
进程是承担分配系统资源的基本实体:
所以进程的作用,就是把代码和数据加载到内存,让0S为该可执行程序申请所匹配的所有资源
那我们之前所提到的进程概念都是错的吗?
并不是,以前所谈的进程只是单纯内部只有一个task_struct(一个执行流)而已,其余都没有变化
但是并非所有操作系统都是这样实现的,Windows操作系统线程的实现就和Linux操作系统线程的实现不同
但无论是哪个操作系统,都需要满足上面所述的线程的概念
它就是类似于一个标准,但具体怎么实现,根据操作系统的不同而不同
就好比我们平时学校说的好学生,成绩优异,作风端正等等,这些评价体系都是相同的,但是落实到每个学校又会有所不同,比如A学校要求成绩前3,才算成绩优异;但是B学校要求成绩前10,就已经算成绩优异了
因此,充分理解规范非常重要
1.线程是一个执行分支,执行粒度比进程更细,调度成本更低
2.线程是进程内部的一个执行流
3.线程是CPU调度的基本单位,进程是承担分配系统资源的基本实体
既然线程是进程内部的一个执行流,那线程的数目必定是大于进程的数目
所以线程也需要进行管理和组织
Windows系统采取的是模仿PCB结构,定义了一个TCB(线程控制块)的数据结构,隶属于进程PCB
用TCB来控制和调度线程
也就是说Windows内核里面有真线程
但是可想而知,这样会带来很多麻烦,线程与线程之间需要进行管理,进程与线程之间需要进行管理等等
但是Linux内核的设计者采取的却是完全不同的策略
线程和进程两者本身就有很多相似之处,并不需要重零开始构建一套全新的体系,我直接复用PCB结构体,用PCB模拟线程的TCB
即Linux没有真正意义上的线程,而是用进程方案模拟的线程
复用代码和结构,最明显的一个优势就是简单!
假如存在TCB,就需要有TCB自己的管理体系,而TCB隶属于PCB,则PCB又要对TCB进行管理
但现在就只有PCB,一切都是原来进程的体系进行设计
所以更好维护,效率更高,也更安全,这就是为什么Linux操作系统可以不间断的运行!即便硬件损坏,可能Linux操作系统也还没挂,但是Windows操作系统,也就是我们平时用的电脑,假如一直开机,不用三天,可能就会出现故障
因为执行流<=进程,因此Linux系统又把线程(执行流)称作为LCB轻量级进程,对应英文Light Weight Process