线程是个啥子东西? 要了解它,我们先得简单了解一下其他的相关的东西.
操作系统
一个计算机系统是硬件和软件组合在一起,我们要想利用这一大堆硬件和软件,就要通过操作系统帮我们管理这些硬件资源和软件资源.(例如种地,硬件资源和软件资源就是田地和水源,操作系统就是我们锄头等工作工具,利用这些工具让这片田地井井有条,让我们收获果实)
目前常见的操作系统有:Windows ,Linux,MacOS,Android 等等 ;
(像我这里的就是Windows的系统)
程序
有了操作系统帮我们管理计算机,我们就可以让计算机帮我们完成一些工作;
对于计算机来说,我们让计算机完成的任务,就可以看成 是一个程序 ;
程序:简单来说就是一组指令 和 一堆指令要处理的数据;
(就像做一盘青椒炒肉,我们要"做"就分为很多步骤,一个个步骤就是一条条指令,青椒炒肉的原材料,就是一堆指令要处理的数据)
进程(process)
简单了解了系统和程序,就可以理解进程; 每个应用程序,都是运行在操作系统上的 ;
而进程: 可以看成是一个 "跑起来的"或是"正在运行" 的 程序;
例如: 电脑上的QQ
(这个QQ.exe , 就是一个可执行程序,还有其他一堆与之相配合文件)
我们双击这个QQ.exe,就可以运行这个程序;
(可以看到我们的桌面右下角,这里有一个QQ的图标)
或者 右击桌面底部的任务栏,可以点击查看"任务管理器"
在任务管理器里,可以看到我们的 QQ.进程
(如果程序是一辆车,那么进程就是一辆已经跑起来的车)
进程的管理
如何管理进程,在系统中有专门的PCB , 来描述线程的属性 ;
PCB(进程控制块)
PCB描述进程的各个属性,一个进程可以由一个和多个PCB来表示;在系统中用类似于"双向链表"这样的数据结构来组织多个PCB ;
(既然进程是"一辆跑起来的车",那么车肯定是有车管所来管理和记录车的相关信息,而PCB就是进程的"车管所")
PCB分这几个部分来描述进程的属性
1. pid(进程标识符)
每个进程的身份标识,每个进程都会有一个pid; (类似于车的车牌号)
2. 内存指针
内存指针是一组属性,描述了进程所持有的"内存资源" ;
3. 文件描述符表
文件描述符表和 文件(硬盘) 有关 , 描述了进程持有的 "硬盘资源";
4. 进程调度
进程调度和进程持有的CPU资源有关.是系统对进程的执行的调度策略,进程调度分为两种
并行: N个进程同时在N个CPU核心上同时执行 ;
并发:有多个进程,这多个进程在一个核心轮流来执行;(但是轮流执行的速度很快,这样在我们看起来,这些进程就好像是在一起同时执行)
怎么理解并行和并发
并行
我们有核心1和核心2两个核心, 有进程A和进程B两个进程; 让进程A和进程B 同时执行 , 进让一个核心处理一个进程即可;
但是这样,有一个问题: 如果我有100个进程 , 我要让这100个 同时执行,上面的方法可行吗?
再次打开我们的任务管理器,在性能里可以看到我们的CPU核心数
这里的逻辑处理器16,一个核心执行一个进程,但是这16个核心,怎么同时执行 100个进程?->并发;
并发
有5个进程,但是核心比较少,只有1个,那么这5个进程就在这一个核心里轮流执行;
5个进程,在核心里快速执行, A->B->C->D->E->A , 这样轮流执行, 像一串珠子连起来旋转,只要执行的快,在我们眼里,看起来就像是5个进程 一起 "同时执行" ;
这里的"同时执行"就像这里虽然只是一个人,但是如果这个人速度快的话,在我们眼里就是多个人
在CPU的视角:5个进程的是轮流执行的,有先后顺序的 ;
在我们的时间:5个人是"同时执行"的,没有先后顺序的;
并发就是这样的一个原理,只要在几个进程轮转的速度够快,在我们眼里这几个进程就是同时执行的;
因为我们CPU的核心有限,不可能每个进程都能放在一个核心上,同时运行,所以并发执行就解决了这个问题;
我们一般所说的并发,指的就是这两个:并行+并发; 用 并发 来代指(并行和并发);
要实现这样的进程调度,PCB引入了一些属性来支持
- 进程的状态(描述进程当前的状态)
就绪状态: 进程已经准备好了,随时可以去CPU上执行
阻塞状态: 因为某个条件不具备,导致进程还不能去CPU上执行.(例如:代码中的scanf,要等到我们输入了,才能够继续)
- 进程的优先级
操作系统在调用多个进程时,有的进程会有更高的优先级,操作系统就会对这些优先级高的进程更偏心,优先调度这些进程
- 进程的上下文
类似于 我们游戏 里的存档 , 读档;
像并发这样,让进程轮流执行的调度模式,在一个进程离开CPU,换另一个进程上CPU上执行前,需要记录一下当前的各种状态,好让下次再轮到这个进程进入CPU里执行时,能够按上次的工作继续往后;
- 进程的记账信息
记账信息,记录当前进程持有的CPU资源情况(例如在CPU上执行了多久了); 记账信息可以作为操作系统调度进程的依据 ;
因为优先级机制,优先级高的进程分配到的资源更多,可能会出现一些极端情况,例如:大部分的资源都给了一个进程 , 但是其他进程的只有一点点; 这时候,操作系统就可以根据记账信息,来调度进程 ;
(回归主题,终于到线程了)
线程(Thread)
线程是轻量级进程,可以把线程看成一个"小进程",线程的体量要比进程的小得多;
为什么要有线程,有进程还不够吗?
前面我们了解了多进程的调度,而多进程就是为了实现"并发编程"(这是我们目前的刚需),但是多进程有一个明显的问题->效率不高;
创建一个进程,销毁一个进程,调度一个进程 这一系列操作 所销毁的时间是比较多的 ;
为了解决这个问题,就引入了-> 线程 ;
线程
线程时"轻量级进程",比进程小得多 (所以线程的创建,销毁,调度 的速度,比进程快的多)
当我们创建一个进程时首先得创建线程, 一个进程里可以包含一个或多个线程;
(像这样一个大方块,是由很多小方块组成; 进程比作是大方块, 而线程就是组成大方块的小方块)
线程的特点
1. 线程都是可以相互独立调度的
进程里的每个线程都可以上CPU去独立调度执行,我们前面了解的对进程的调度,其实就是对进程里的线程进行调度执行;多个进程的并发执行,其实是对多个进程里的多个线程进行并发执行;
(线程去调度执行了,进程呢?当进程里的 线程独立调度执行,系统就不考虑 进程这个概念了, 系统对这些线程的 操作,其实就是对这个进程的操作.)
(一块大田地,分成一块块小田地,我们往小田地里种菜,其实不就是在这大田地里种菜麻)
2.线程也由PCB表示
前面我们了解的一个进程有一个或多个PCB表示,其实应该PCB就对应到一个线程,一个进程有多个PCB,就是 这些PCB对应到进程里的多个线程;(同样进程调度里的各个属性,线程里也有);
3. 同一个进程里的多个线程,共用同一份资源
在同一个进程里,有多个线程的话,那么这些线程就共用同一份内存空间,文件资源等;(所以创建线程不需要重新申请内存,直接用进程的资源,省去了分配资源的开销,效率更高了);
(创建一个进程,就要申请一块资源给进程)
(而创建一个线程,就直接把进程里的资源给线程即可,不需要申请资源)
4. 进程是资源分配的基本单位,线程是调度执行的基本单位
系统分配资源,是按一个进程为单位,来进行分配的,后面创建线程是不会再去分配资源;
系统对进程的调度,其实是对进程里的线程进行调度 ;
线程和进程的关系
1.进程里包含线程,一个进程里可以有一个或多个线程,一个进程最少要有一个线程;
2.进程和线程都是为了实现并发编程的; 但是线程是轻量级的进程,比进程要"小"得多;
3.一个进程里的线程,它们是共用着同一份资源的;
4. 进程是资源分配的基本单位,线程是调度执行的基本单位 ;
5.一般来说,进程和进程之间,是互相独立的,一个进程不会影响到其他的进程;但是,同一个进程里的线程,这些线程和线程之间是可能会互相影响的;(就像一块田(进程)里,我这边种玉米(线程1),那边是丝瓜(线程2),这丝瓜长到玉米那里去了,把玉米压死了,就是出现异常了);
总结
进程里包含线程(每个进程最少有一个线程) => 一个进程有PCB来表示(而一个PCB就表示一个线程) => 这些PCB都共用同一个内存指针,文件描述符表等属性 => 每个线程都有自己的 状态,上下文,优先级等属性 => 每个线程都可以独立在CPU上调度执行=> 创建线程不需要 重新申请资源 =>使用线程可以提高效率,但是线程数目要有限制,不能无限增加(线程多了容易出现问题,如果线程出现问题,可能会影响整个进程);