线程的引入
从20世纪60年代提出进程的概念之后,使得多个程序可以实现并发执行(单CPU中),改善了资源的利用效率,提高了系统的吞吐量。此时进程作为系统中的一个基本单位,具有两个属性:
进程作为资源分配和拥有的基本单位
进程是一个可以独立调度和执行的基本单位
进程的这两个基本属性构成了进程并发执行的基础,但是在进程的推进过程中,系统必须进行一系列的操作,如创建进程、撤销进程、切换进程等。由于进程是一个资源的拥有者,所以在执行这些操作的时候系统要进行资源的分配与回收,现场的保存与恢复等工作。系统为此要付出较大的时间与空间开销。
综上所述:在系统中所设置的进程数目不能过多,进程切换的频率也不能过高,这就限制了系统并发程度的进一步提高
那么如何能使进程更好的并发执行,同时又能尽量减少系统开销呢 一些大佬设想将进程的两个属性分开,由操作系统分别处理,即只作为资源分配与拥有的基本单位,不再是调度和执行的基本单位,使之轻装前进;而对资源分配与拥有的基本单位,不进行频繁的切换处理,以减少系统开销。正是因为这些思想,产生了线程这一个新的概念
线程概念
- Linux系统下用pcb来模拟实现线程,因此Linux下的线程实际上是一个轻量级进程(我们都知道pcb也是进程,那么在这是不是有点懵了呢?接下来为你们解答)
一、通过上面两个图中我们可以看到进程有自己独立的虚拟地址空间(mm_struct),而线程共用进程的虚拟地址空间
二、通过进程地址虚拟地址空间,可以看到进程的大部分资源,将进程资源合理分配给每一个执行流,就形成了线程执行流
- Linux下的线程共用大部分进程资源,相较于传统进程更加轻量化
- 进程是资源分配和拥有的基本单位,而线程是进程中的一个实体,是被系统独立调度和执行的基本单位
- 线程自己基本上不拥有系统资源,只拥有在运行中必不可少的一点资源(如程序计数器、一组寄存器和栈)但是它可以与同属于一个进程的其他线程共享进程所拥有的全部资源
- 一个线程可以创建和撤销另一个线程,同一进程中的多个线程之间可以并发执行。线程之间也会相互制约,使其在运行中呈现异步性,因此线程同样具有就绪、执行阻塞三种基本状态
线程的优缺点
优点:
- 创建一个新线程的代价要比创建一个新进程小很多
- 与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多
- 线程占用的资源要比进程少很多
- 能充分利用多处理器的可并行数量
- 在等待慢速I/O操作的同时,程序可执行其他的计算任务
- 计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现
- I/O密集型应用,为了提高性能,将I/O操作重叠。线程可以同时等待不同的I/O操作
缺点
- 缺乏访问控制
- 进程是访问控制的基本粒度,在一个线程中调用某些OS函数会对整个进程造成影响
- 健壮性降低
- 性能损失
- 增加了额外的同步和调度开销,而可用的资源不变
- 编程难度提高
线程VS进程
- 调度。原有的系统中进程既是资源分配和拥有的基本单位,又是独立调度和执行的基本单位,极大的限制了系统的并发程度。在引入线程之后,把线程作为独立调度和执行的基本单位,而进程只作为资源分配和拥有的基本单位,把传统进程的两个属性分开,使得系统的并发程度显著提高。此时在同一进程中,线程的切换不会引起进程的切换,而由一个进程中的线程切换到另一个进程中的线程时,将会同时引起进程的切换
- 并发。在引入线程的系统中,不仅进程之间可以并发执行,而且在一个进程中的多个线程之间也可以并发执行,使系统具有更好的并发性,从而能更有效的使用系统资源和提高系统吞吐量
- 拥有资源。不论是传统的操作系统还是引入线程的操作系统,进程都是资源分配和拥有的基本单位,而线程基本上不拥有系统资源(只有一些运行时必不可少的资源),但是线程可以访问所属进程的所有资源
- 系统开销。系统在创建(或撤销)进程时,都要为之分配(或回收)大量的资源。如主存空间/IO设备等。所以要在进程切换时进行复杂的现场保护和新环境的设置。因此不管是进程的创建、撤销还是切换,对于进程的操作所付出的系统开销都远大于对于线程操作所付出的系统开销