一、理解线程的思想
线程就是把一个进程分成多个执行部分,一个部分就是一个线程,比如可以让一个线程负责一个函数的执行。
用工厂的生产流水线来说:一条生产线一天制造10个产品。A厂有10条生产线,B厂有1条,A厂的生产效率自然是要比B厂好的。而进程就像是工厂,线程就像是流水线,流水线数量多,自然工厂的生产效率也更高。
但流水线的数量也不是越多越好的,流水线也是有成本的,流水线越多,成本也越高。因此我们要对效率和成本进行综合考虑,找到一个最适合的流水线数量。
线程数量也是同理,线程数量越多,系统负荷就越大,因此要找到线程的合适数量,这样才能获得最大的效率。
二、Linux中的线程与进程
1.Linux中的进程
在最开始学习的时候,进程就是pcb。在Linux中进程pcb是一个task_struct结构体,是操作系统对于程序运行的动态描述,系统通过进程pcb进行程序调度和管理。
2.Linux中的线程
将整个进程的任务分成若干条执行流,每条执行流就是一个线程。但是Linux中,其实并没有线程这个概念,因此并没有描述线程信息的结构体。
虽然Linux中没有线程这个概念,但是总不能不用线程。因此线程的pcb结构体也是task_struct结构体,和进程是一样的,所以Linux中的线程又被称为轻量级进程。
而我们之前学习的进程,其实就是只有一个线程的进程。在开始接触线程后,进程中就包含了多个线程(轻量级进程),因此一个进程也就包含了多个pcb,这些pcb共享进程中的大部分资源。
三、线程的工作方式
多个线程是如何共同执行一个进程的?
(1)每个进程都有独立的虚拟空间,但线程不是。同一个进程下的多个线程pcb通过同一个虚拟地址空间映射,执行一个进程中的不同部分。
(2)同一个进程下的线程使用同一个虚拟空间和页表。因为每个线程都负责了程序的一部分,如果单独给每个线程分配虚拟空间和页表,那线程和进程就没区别了。
四、线程的独有数据与共享数据
虽然一个进程下的多个进程共享同一个虚拟空间和页表,并且线程之间共享大部分数据。但每个线程也是有自己的隐私的,因此线程的数据分为共享数据和独有数据。
1.独有数据
线程的独有数据:标识符,上下文数据,程序计数器,栈,信号屏蔽字,errno
- 标识符:用来区分线程的标志,也就是线程pcb的pid。
- 上下文数据:每个线程都要记录自己处理完的数据,正在处理的数据,将要处理的数据。
- 栈:因为多个线程共用同一个虚拟空间和页表,避免造成调用栈混乱,线程要有独立的栈。
- 信号屏蔽字:即信号阻塞集合。每个线程都有两个信号阻塞集合:一个是进程的阻塞集合,代表该进程下的所有线程都要阻塞的信号。一个是每个线程独有的信号阻塞集合,代表各个线程自身要阻塞的信号。
- errno:全局变量,存储错误编号,每个线程pcb中都有。
为什么信号阻塞集合要独有?
因为CPU的分时机制,程序是切换运行的。进程收到的信号所有线程都可以处理,但某些线程可能工作比较繁忙,如果让它们处理信号,可能会降低它们的工作效率。因此就给每个线程设置了独立的信号阻塞集合,让每个线程只处理规定让它们处理的信号就好。
2.共享数据
线程的共享数据:虚拟地址空间,IO信息,信号处理方式,工作路径。
- 虚拟地址空间:同一个进程下的多个线程之间通过共享同一个虚拟地址空间和页表来执行进程中的不同部分。
- IO信息:同一个进程中的所有线程,都共享了IO信息,A线程打开的文件,B线程也可以访问。
- 工作路径:默认情况下,程序运行的地方就是工作路径,通常需要设置。