线程再谈
引言
大概一年前,写了一篇‘线程入门’,现在回头看看,虽然语言通俗,但始终让我觉得不满意。也许,类比用得太多,观者虽然能够大概理解关于‘线程’的概念,不如说,观者把‘线程’关联到了类比上,但还是没有贴近‘线程’的本质知识。现在,经过项目的锻炼,以及知识的积累,我相信我能把关于线程的知识讲得更加透彻,更加贴近本身。
任务调度
这里首先讲下计算机硬件组成的基本知识。
![](https://pic3.zhimg.com/80/8bf6ef80ddbcd9ed5984fe9a51bb5b78_hd.jpg)
所有的软件就运行在上面,相关知识不深入展开了。我们只要知道,CPU(中央处理器)太快,太快,太快了,寄存器仅仅能够追的上他的脚步,RAM 和别的挂在各总线上的设备完全是望其项背。那当多个任务要执行的时候怎么办呢?轮流着来?或者谁优先级高谁来?不管怎么样的策略,一句话:在 CPU 看来,就是轮流着来。
注意,需要声明的是,这是单核 CPU。单核(非 SMT )确实是靠划分时间片的方式让多个进程“同时”运行起来,需要排队。多处理器和多核以及 SMT 技术出来后,有几个核就可以同时处理几个进程,多出来的进程/线程也是要排队,和单核是相同的。
操作系统(如 Windows 、Linux) 的任务调度是采用时间片轮转的抢占式调度方式,也就是说一个任务执行一小段时间后强制暂停去执行下一个任务,每个任务轮流执行。任务执行的一小段时间叫做时间片,任务正在执行时的状态叫运行状态,任务执行一段时间后强制暂停去执行下一个任务,被暂停的任务就处于就绪状态等待下一个属于它的时间片的到来。这样每个任务都能得到执行,由于CPU的执行效率非常高,时间片非常短,在各个任务之间快速地切换,给人的感觉就是多个任务在“同时进行”。
那么单个时间片内 CPU 是怎么在工作的呢?
执行一段程序代码,实现一个功能的过程介绍 ,当得到 CPU 的时候,相关的资源必须也已经就位,就是显卡啊,GPS 啊什么的必须就位,然后 CPU 开始执行。这里除了 CPU 以外所有的就构成了这个程序的执行环境,也就是我们所定义的程序上下文。当这个程序执行完了,或者分配给它的 CPU 执行时间用完了,那它就要被切换出去,等待下一次 CPU 的临幸。在被切换出去的最后一步工作就是保存程序上下文,因为这个是下次它被 CPU 临幸的运行环境,必须保存。
简单来说:
进程
那么进程是什么?
进程时间包括上下文切换的程序执行时间总和 = CPU 加载上下文 + CPU 执行 + CPU 保存上下文,进程也就是这个过程。
那进程的特性很轻易就理解了:
- 动态性:进程是程序的一次执行过程,是临时的,有生命期的,是动态产生,动态消亡的;
- 并发性:任何进程都可以同其他进程一起并发执行;
- 独立性:进程是系统进行资源分配和调度的一个独立单位;
- 结构性:进程由程序、数据和进程控制块三部分组成。
线程
那么线程是什么?
进程的颗粒度太大,每次都要有上下的调入,保存,调出。如果我们把进程比喻为一个运行在电脑上的软件,那么一个软件的执行不可能是一条逻辑执行的,必定有多个分支和多个程序段,就好比要实现程序A,实际分成 a,b,c等多个块组合而成。那么这里具体的执行就可能变成:程序A得到 CPU → CPU 加载上下文,开始执行程序A的a小段,然后执行A的b小段,然后再执行A的c小段,最后CPU保存A的上下文。这里a,b,c的执行是共享了A的上下文,CPU 在执行的时候没有进行上下文切换的。这里的a,b,c就是线程,也就是说线程是共享了进程的上下文环境的,更为细小的 CPU 时间段。
线程与进程
进程和线程就是这样的背景出来的,两个名词不过是对应的 CPU 时间段的描述,名词就是这样的功能。进程和线程都是一个时间段的描述,是 CPU 工作时间段的描述,不过是颗粒大小不同。