【Linux】线程概念

什么是线程?

常见的概念
线程是比进程更加轻量级的一种执行流

线程是进程内部执行的一种执行流

  • 线程是CPU调度的基本单位
  • 进程是承担系统系统资源的基本实体

下面来解释这些概念


线程

进程=内核数据结构+代码和数据

一个进程的创建伴随 PCB创建,进程地址空间的创建,页表的映射。同时还会加载动态库。

然后将进程PCB链接到调度队列中,等待被调度。

每个进程都有独立的地址空间和页表,还有一套独立的寄存器。因此进程是互相独立的。

为了减少“成本”,子进程我们只创建PCB,将PCB链接到同一份地址空间后。并且通过方法,将正文代码分发给不同的“子进程”执行,对此原本的代码就被分发成“子进程”的执行。我们这里的子进程实际上就是线程!

对此每一个线程都是一个执行流。线程是进程内部的执行流!


重新定义进程

现在我们将所有的PCB、进程地址空间、页表统一叫做进程。

之前我们说的进程其实就是单执行流,只有一个线程。当内部有多个执行流时,就是多线程。

进程向系统申请的资源,在内部被线程瓜分了,进程是系统资源分配的基本实体! 

时间片也是资源,被进程瓜分。线程再去进程平均分享时间片。

而在Linux中,其实是没有线程这个概念的,因为线程和进程的调度,阻塞的控制块是类似的,换言之,Linux不创建线程专属的方法,沿用进程的方法。一套代码就能实现进程和线程。为此,线程又叫做轻量级进程。

所以在Linux中不识别线程和进程!

CPU只关心执行流,因此线程是CPU调度的基本单位!


如何理解线程比进程的效率更高

  • 资源开销小,线程创建只需要分配相应的寄存器和栈,进程还需要分配内存空间,文件等资源。线程相应的寄存器比进程少,跳转少,速度更快。
  • 局部性原理,数据交互快。进程之间无法共享内存,CPU的cache会预加载热数据,就是提前加载被访问数据的下文,命中的概率是大的。线程之间不需要重新加载cache寄存器。而进程是不共享数据,每一次切换都需要重新加载cache。


页表的补充

磁盘上的程序应该是被划分成4kb大小的页帧,加载程序时,是4kb的加载。

在物理内存中,应该也被划分成4kb的页框。

磁盘和物理内存的数据交换就是4kb进行的。

如果我们想要修改磁盘上1字节的数据。我们必须将4kb都加载到内存中,修改,写入。


 二级页表

虚拟地址到物理地址的转化

一个虚拟地址有32位,这32位并不是全部用来表明地址

虚拟地址被分成 10+10+12

页目录

假设4GB的物理内存

前10位地址作一级页表的索引

需要10个比特位,找到是哪一个页表项(一级页表)

实际上一级页表话包括是否命中,是否可写等

如果s保存的是一个常量字符,在通过虚拟地址到物理地址的映射时,会被标志位不可写

再后续通过页表跳转时,会读取到只有可读权限,如果试图修改常量,OS触发信号终止程序。


页表

中间十位(二级页表索引)找到具体的页框项

通过10位的物理地址,就能找到对应页框的4KB


页内偏移

4KB=1024*4=2^12次方

因此只需要12位bit位就能表示4KB里的每个字节

故访问到物理内存就是通过起始地址+偏移量

我们创建的内置类型 如int 实际上类似就是偏移量的多少。

CPU里面有寄存器保存了页目录的地址。eip寄存器保存了虚拟地址,通过MMU寄存器转化到物理地址。所以我们平常看到虚拟地址,底层看到物理地址。

实际上,加载页表时,也遵循局部性原理。会根据需要加载需要内容附近的页目录。如果不命中,再记载另一块。

缓冲区就是指针指到一块空间上。


 缺页中断

软件试图访问已经映射的虚拟地址时,但当前并未被加载到物理内存的页框时。

OS会检测到缺页中断,调取内容,加载到内存上。

当调用完加载后,会继续执行当前指令。


线程的优点

创建线程的成本低:寄存器,地址空间,页表,动态库等

切换开销小:共享内存切换少量寄存器,页表切换开销小,不需要重新分配内存、文件。

线程占的资源更少

充分多核并行

提高相与速度:等待慢速IO时,程序可以执行其它计算任务

计算密集型:将计算分到多个进程

IO密集型:可以等待多个IO操


线程的缺点

性能损失:线程调度和上下文切换可能会导致性能损失。频繁切换线程会导致性能下降。

健壮性降低:共享了不该共享的变量导致相互影响的可能性很大,需要线程保护。

例如:一个线程异常终止,会导致所有线程终止。(线程异常

访问缺乏控制:堆,静态区的数据会被所有线程访问到,缺乏控制。

编程难度高


线程和进程的对比

进程是资源分配的基本实体

线程是调度的基本单位

线程共享进程的资源,但也有独立的数据

  1. 独立的寄存器:线程再运行时会用到各种寄存器,如计数、栈指针。由于线程是并发的,每个线程都必须有独立的寄存器来保持上下文信息
  2. 独立的栈:函数的返回值,局部信息需要被栈保存,因此有独立的栈。
  3. 线程ID
  4. errno
  5. 信号屏蔽字
  6. 调度优先级

线程和进程共享

进程的代码段:任何一个线程可以执行进程中的函数

进程的公有资源:全局和静态变量,堆

进程的其它资源:打开的文件,动态库链接。

地址空间、页表。

  • 25
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深度搜索

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值