线程的认识,本质,和进程的区别,哪些结构是共享/独立的,切换成本,不同os下的线程

目录

再次认识进程

用户视角

内核视角

引入线程 

概念

调度的基本单位 

模拟出图像

思考

线程的本质

线程和进程的区别 

线程哪些结构是共享的

引入

地址空间

系统资源

​编辑

线程哪些结构是单独拥有 

引入

地址空间

系统资源

线程间切换的成本更低

linux和windows下的线程


再次认识进程

用户视角

  • 之前我们对进程有一个概念,进程 = 进程相关内核数据结构 + 代码数据:
  • 这些都是我们可以看到的,进程确实有代码数据,有task_struct等等结构:

内核视角

  • 我们看到的那些,都是必须占用内存资源,否则凭什么可以被我们看到
  • 并且,进程包括的这些内容,都必须一起被开辟空间,不然单独申请一个页表或者别的属实没啥用
  • 也就是说 -- 我们申请资源时,都是以进程为单位
  • 说的高级一点就是 -- 进程是承担分配系统资源的基本实体

引入线程 

概念

  • 指一个程序里的一个执行路线
  • 多线程可以实现并发执行,它使得程序能够在同一进程内并发执行多个任务
  • 每个线程都可以独立执行不同的部分,从而使得多个任务可以同时进行,提高了程序的整体性能

调度的基本单位 

  • 之前我们曾说,cpu调度时,调度的是进程
  • 这里说的更清晰一点,其实调度的是task_struct

模拟出图像

通过从上面的概念,我们可以模拟出它在内核中的样子:

思考

我们是如何得到这幅图像的呢?

由于线程可以执行任务,且cpu调度的单位是pcb

  • 所以我们的线程至少需要一个pcb

因为线程可以在进程内执行任务

  • 所以首先明确,线程是囊括在进程范围内的
  • 不然如何拿到进程的资源呢?

因为执行的是进程派给它的任务

  • 所以线程可以直接使用进程的数据结构和资源
  • 因为进程在申请空间时,就已经创建过了,不需要线程再创建

因为在进程内执行

  • 进程内,实际上就是在进程的地址空间上执行
  • 因为线程执行任务用的就是进程的地址空间

然后将当前进程的资源分配给线程,这样线程就可以执行分配给他的那一部分的代码

通过cpu的调度,就可以实现并发

线程的本质

从图上来看,那些task_struct其实就可以被看作是线程

  • 因为比起进程来说,线程只是创建出更多的task_struct

前面说过,cpu调度的是task_struct

  • 那么也可以说 -- cpu的调度单位是线程
  • 其实cpu不关心它调度的是进程还是线程,它只认pcb

因为线程是cpu调度的基本单位

  • 所以线程也可以被叫做是进程内部的执行流

并且,线程的资源来自于进程,进程的资源来自于内核,这是有先后顺序的

线程和进程的区别 

这张图是我们之前认识的进程,一个进程只有一个pcb:

今天我们拓展了进程的概念,它可以拥有多个pcb,一个pcb就是一个线程:

通过这两张图我们可以发现:

  • 我们介绍的线程在调度时,和之前认识的进程,流程是一样的,将虚拟地址转换为物理地址,然后进行访问
  • 唯一不同的就是pcb的数量不同(也就是内部执行流数量不同)
  • 所以,我们之前学习的进程,实际上就是只拥有一个线程的进程
  • 下面那张图属于单进程多线程的进程

线程哪些结构是共享的

引入
  • 线程的资源都来源于进程
  • 为了更好的执行任务,很多资源都是被线程共享的
  • 比如多个线程共用一个地址空间
地址空间

所以,对于地址空间来说(从下往上看):

  • 代码区肯定是共享的,毕竟线程要执行的任务需要用到代码区的数据(比如函数,线程是可以调用的)
  • 全局区也是共享的,线程可以拿到全局变量
  • 堆区也是共享的,线程可以访问堆区上已经开辟的空间,但是一般访问不到(因为访问空间需要拿到起始地址)
  • 共享区肯定是可以共享的,他本来就是用于进程/线程共享的
系统资源
  • 这些基本的系统资源,都是共享的
  • 毕竟线程是用来完成同一进程的任务的,有些数据还是统一的比较好

线程哪些结构是单独拥有 

引入
  • 难道所有资源都是共享的吗?
  • 肯定不是这样的
  • 因为不同的线程执行的任务一般是不一样的,拥有的上下文数据肯定也不一样
地址空间

  • 栈区是不可以共享的,因为任务用到的变量肯定是不一样的
  • 所以要为每个线程分配不同的栈区域
系统资源
  • 因为执行的任务不同,线程也不同
  • 为了区分每个线程,以下资源是不可以共享的

  • 线程id用于区分线程,就像进程pid一样
  • 寄存器用于存放上下文数据,肯定要为每个线程单独配套,不然就乱了
  • 每个线程的状况不同,errno,信号屏蔽字,优先级自然也要不同

线程间切换的成本更低

为什么会这样说呢?

  • 切换的时候,是需要更换上下文数据的,不同的进程用到的资源一般不同,所以需要全部切换
  • 但是,线程的切换不需要切换地址空间和页表,以及其他的一些资源

当然,这些都只占原因的一部分,最大原因在于cpu的缓存机制:

  • 如果cpu直接与硬件交流,效率会很低,会耽误cpu的执行(因为要等待外设读取成功)
  • 所以cpu内置了cache,作为中间介质,提高io效率
  • 它会根据局部性原理,将内存的部分数据预读到cpu内部,方便cpu读取

  • 对于线程之间切换,他们很可能会用到相同的数据,所以缓存中的数据不会清除
  • 对于进程来说,由于进程的独立性,每次进程切换,都需要重新预读数据

linux和windows下的线程

  • 所以,linux下是没有真正意义上的线程结构的
  • 他是用pcb模拟出线程,而不是单独定义一种结构
  • windows下有真正的线程结构
  • 这两者比起来,linux中的线程执行任务时更加轻量化

为什么这么说呢?

  • windows中有单独的数据结构,那么在调度时,就会比linux更加频繁的切换上下文
  • 维护的成本也更加高(比如创建/释放线程,管理线程),而不像linux中,直接复用管理task_struct的方式即可

这样会造成什么结果呢?

  • 就是因为windows中调度时,数据结构更加复杂,所以它不能长时间运行,不然肯定会出问题
  • 而linux可以一直运行很久 

所以,我们一般将linux中的的进程,称为轻量化进程

  • 就是因为它和单独定义了线程结构的操作系统比起来,运行更加轻量化 :
  • 在linux的cpu眼中,它看到的pcb的量级 <= 线程拥有单独数据结构的系统中的pcb
  • 其他系统的pcb,代表的是完整的一个进程
  • 而linux中的pcb可能只代表进程中的一个执行流,那么它要调度的资源就比完整进程的要少 ; 也可能代表的也是完整进程,那么此时量级就相等了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值