我之前说到了进程的管理,进程间通信,以及信号。今天我们聊一下线程。
什么是线程
我们知道程序是机器指令和数据的集合,这些指令和数据是磁盘上的一个可执行映像。而进程是程序的一个执行实例,是为了完成我们的计划的动态实体。操作系统为了描述这个动态的实体不得不使用一些额外的数据(进程pcb,寄存器的值等),这些多出来为了管理进程的数据也就成了进程与程序间的根本区别点。所以我们说:进程是承担分配系统资源的基本实体
那么进程和今天的线程有什么关系呢?当然有关系!下面是线程的概念:
- 我们将一个程序里的执行路线叫做线程(thread)。更准确的定义是:线程是一个进程内部的控制序列
- 一切进程都至少有一个执行线程
- 线程在进程内部运行,本质在进程的地址空间内运行
- 在Linux系统中,并没有真正的线程只能用进程PCB来模拟线程,所以在CPU眼里,看到的PCB比传统的进程更加轻量化
- 透过进程虚拟地址空间,可以看到进程的大部分资源合理分配给每个执行流,从而形成线程执行流
所以线程其实是调度的基本单位,它与进程之间是多对一的关系。
线程的优点
线程比进程更轻量化也就说明它一定是有优点的。
- 创建一个新线程的代价要比创建一个新进程的代价要小的多,这点不难理解,因为多个线程共享进程的一份资源,所以占用操作系统的资源也更少
- 与进程相比,线程之间的切换要比进程简单的多,因为当操作系统在对不同的进程进行切换时要切换他们的进程地址空间,页表等上下文信息,而线程却不需要切换
- 能充分的利用多处理器的可并行数量
- 在等待慢速IO的操作结束的同时,程序可以执行其他的计算任务
- 计算密集型应用,也为了能在多处理器系统上运行,将计算分解到多个线程中实现
- IO密集型应用,为了提高性能,将IO操作重叠。线程可以同时等待不同的IO操作
这里计算密集型是指程序中充满大量计算的程序,而IO密集型是指程序要经常发生IO操作,但是其实线程主要的优点还是创建代价的减小和线程切换的代价减小
线程的缺点
- 健壮性降低:我们上面一直在强调线程是进程内部的一个执行流,线程与进程不相同的是,进程运行时具有独立性,如果子进程由于某种错误或者异常退出,此时并不影响父进程。但是线程不一样,如果某个线程出现了异常,那么会导致整个进程退出。
- 缺乏访问控制:线程共享进程的资源,所以这些资源被称为临界资源,如果我们对这些临界资源没有正确的访问控制,那么将可能产生不可预知的后果
- 编程难度提高:上面种种缺点最后都会导致程序员在编写多线程程序时难度大大的提高,稍不留神就会出现线程异常的问题
进程和线程的区别
进程是承担系统分配资源的实体,线程是CPU调度的基本单位
这句话一定要记住!!这是二者最本质的区别!!!
线程总是共享进程的数据资源,但是也有自己的一部分私有数据,那么该怎么区别呢?
独立资源: 线程ID,一组寄存器(因为线程要被调度,所以他需要记录硬件上下文),自己的栈结构,调度优先级,信号屏蔽字
共享资源: 文件描述符,每种信号的处理机制,当前工作的目录,用户id和组id,代码和数据
对上面概念还是不清楚的伙伴,我再举个例子:
假如学校要大扫除,学校分给每个班一个卫生区及相应打扫卫生的工具,每个班的老师又给每个同学分配了工作。
这里学校面积类比是系统资源,每个班就是学校分配任务的基本实体类比进程,每个同学就是调度的基本单位类比线程。分给班的卫生工具就是共享资源,但每个人的工作方式和方法各不相同是独立资源。
接下来再理解一下线程相关概念:
还是上面的例子。每个班同学的共同目标都是将卫生打扫好(调度),但如果班里有同学卫生没做卫生(线程异常),学校会直接通报你这个班(进程崩溃),但其他班同学不会受到影响(进程独立)。
线程异常的过程:
线程是进程的执行分支,线程出异常,就类似于进程出异常,进而触发信号机制,接着会终止进程。然而进程终止后,进程内所有执行的线程都会退出。
线程的概念先到这里,接下来有一些关于线程的问题,比如线程的控制,线程的互斥,线程的同步,生产者消费者模型(基于阻塞队列的、基于环形队列的)等问题,我会在在之后的博客依次总结,记得关注我哈~