目录
线程概念
真-线程概念:
- 线程在进程内部执行,是OS调度的基本单位。
- 线程是进程的一个执行分支,是在进程内部运行的一个执行流。
- 在一个程序里的一个执行路线就叫做线程(thread)。更准确的定义是:线程是“一个进程内部的控制序 列”。
- 线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
历史上:
早期,操作系统中是没有线程的,也就是只有进程这个概念,一个进程内只有一个执行流。:60年代,在OS中能拥有资源和独立运行的基本单位是进程,然而随着计算机技术的发展,进程出现了很多弊端,一是由于进程是资源拥有者,创建、撤消与切换存在较大的时空开销,因此需要引入轻型进程;二是由于对称多处理机(SMP)出现,可以满足多个运行单位,而多个进程并行开销过大。
因此在80年代,出现了能独立运行的基本单位——线程(Threads)。
线程有着自己的特点,比如执行粒度更细,更轻量化,调度切换的开销更小等等,而不同操作系统设计线程时有着不同的方案,Windows对于线程,设立了全新的数据结构,进程和线程划分的很清晰,这是比较复杂的。而因为线程创建,执行,切换,销毁等等很多行为都和进程有着很大的相似性,因此Linux采用了用进程模拟线程的设计方案(实现了进程内核代码的复用),这样的设计方案虽然没有为线程设计全新的数据结构,但是最终设计出的“轻量级进程”依旧符合线程的要求。
示意图:
上图为学习线程之前,进程加载运行的示意图,每个进程都有一个task_struct(Linux),即进程PCB。
Linux线程的原理:
Linux线程原理:OS内,如果我们创建“进程”时,不创建新的地址空间,用户级页表,不进行IO将程序的代码和数据加载到内存,只创建task_struct,让这个新的PCB指向旧的PCB(创建此新线程的主线程)指向的地址空间mm_struct,再通过一定的技术手段,将当前进程的资源合理划分给不同的task_struct,此时,这里的每一个task_struct,就称为一个线程。
- 线程在进程内部执行,指的是线程在进程的地址空间内运行。
- 每个进程内至少有一个执行线程(一个执行流)
- 在Linux系统中,在CPU眼中,看到的PCB都要比传统的进程的PCB更加轻量化,因此将Linux下的进程统一称之为轻量级进程。(多执行流时,PCB task_struct占用整个进程的一部分资源,当然轻量化)
- 之前一个进程,代码执行流程一定是按顺序执行的,多线程之后,就可以进行资源划分,所有线程共享一个地址空间,一个页表。此时的执行就由串型执行变为并发执行,效率更高。
- 我们之前所写的程序为内部只有一个执行流的进程。而多线程即内部具有多个执行流的进程。重新理解定义task_struct:进程内部的一个执行流(Linux下)
- CPU调度的基本单位是线程,OS调度的基本单位是线程。但并不是OS只能调度线程,实际上OS也是可以以进程整体为单位进行调度的。(见下方疑问)
重新理解进程的概念:
如上红色区域即进程全部。
从用户视角来说:进程=内核数据结构+进程对应的代码和数据(内核数据结构中PCB的数量>= 1)
从内核视角来说:进程:承担分配系统资源的基本实体。(因为在进程创建时,系统给这个进程分配资源。而线程是使用创建此线程的进程的部分资源,进程进行资源分配,分配给线程。故进程才是承担分配系统资源的基本实体)
疑问:
对于线程这块我有个疑惑,既然CPU和OS调度的基本单位是线程,且一个进程内至少有一个执行线程(一个执行流),那能不能说CPU和OS只能调度线程呢,也就是理解为CPU调度一个单执行流进程时,本质上也是调度此进程内的一个执行线程?
cpu调度的最小单位_为什么说线程是CPU调度的基本单位?_兮辞之曰的博客-CSDN博客
调度是一方面,另一方面是调度的目的是什么。如果调度的目的是为了让执行流去执行,那肯定是让线程去跑。而如果目的是以进程整体为单位进行资源分配,则OS也是可以做到调度整个进程的。对于CPU来说,特别是Linux下,CPU并不关心线程还是进程,它只关心task_struct,因为在Linux下,只存在轻量级进程,不存在线程。只是用轻量级进程去模拟线程。
(这块实在有些抽象,且学的不是很多,之后再慢慢理解吧)
线程优缺点:略了
不想弄,不想弄,不想弄。
进程vs线程
进程是资源分配的基本单位,线程是调度的基本单位。
线程如何看待进程内部的资源:
进程内的所有线程共享同一个进程地址空间,则其中的代码区,全局数据区,共享区,命令行参数和环境变量,内核区都是共享的。而对于堆区和栈区,根本上来说是共享的,因为一个线程可以将栈帧内的局部数据或堆区开辟空间的地址通过全局数据的方式传递给其他线程,其他线程也可以访问。但是一般情况下我们不会这样做,所以也可以认为栈区和堆区是线程私有的。