线程概念
什么是线程
线程是进程中的一条执行流,执行程序中的某部分代码。linux下没有具体实现的线程,只有库函数用pcb来实现的线程,所以可以认为,每个pcb就是一个线程,所以进程中都至少有一个线程,这些PCB共用进程中的同一个页表和虚拟地址空间,比传统的进程更加轻量化,所以这些线程在linux下也被称为轻量级进程。
PCB也就是进程控制块,在Linux下PCB可以实现对程序的调度运行,所以可以将其作为一个执行流,来实现线程
为什么要使用线程呢?
- 创建一个新线程的代价要比创建一个新进程小得多
- 与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多
- 线程占用的资源要比进程少很多
线程与进程
线程与进程
进程:是一个程序的动态执行,是系统资源分配的基本单位
线程:线程是进序中的一条执行流,是CPU调度的基本单位
我之前博客提到的进程其实都是单线程的进程,在linux其实每个pcb就可以理解为一个执行流,也就是一个线程
从这两幅图可以看出来,linux下的进程其实是一个线程组,一个进程中可以包含多个线程,每一个线程都是进程中的一条执行流(PCB),这些线程在进程的内部运行,本质也就是在进程的虚拟地址空间中运行
线程之间共用进程中的同一个虚拟地址空间,通过同一个页表来完成映射
线程间的独有与共享
既然线程都处于同一个进程中,共用同一个虚拟地址空间和页表,那么它们之间还有哪些数据共享,哪些数据独有呢?
独有:
- 标识符(唯一的标识符来区分线程)
- 栈(独有的函数栈,防止调用栈紊乱)
- 寄存器(也就是PCB中的上下文数据,程序计数器,内存指针等)
- 信号屏蔽字(因为信号会打断进程当前操作,让他优先处理信号,但是一个信号只需要一个执行流去执行即可,如果不想该线程被打断,则对该信号屏蔽,让其他线程去执行)
- errno(系统调用完毕后重置的一个全局变量,防止被其他线程覆盖)
- 优先级(各有各的调度优先级)
共享
- 虚拟地址空间(代码段/数据段, 线程之间数据和代码都共享)
- 文件描述符表(io信息)
- 信号处理方式(信号是针对整个进程的,所以处理方式应该都一样)
多线程与多进程
如果需要进行多任务处理,有两种方法,一种是多线程,一种是多进程
多进程
多线程
多线程的优点:
- 线程的创建和销毁成本低(从上面的图可以看出来,创建多个线程只需要创建多个PCB)
- 线程间调度成本低(使用同一个页表,调度切换时不用切换页表)
- 线程间通信更加灵活(共用同一个虚拟地址空间,数据段共享,只需要获取地址即可访问数据)
多进程的优点:
- 更具有健壮性,更加稳定(因为异常,系统调用,信号等都是对整个进程生效,一旦出现进程出问题会影响所有线程)
共同优点
- IO密集型程序:多任务并行处理(单磁盘可以并行压缩IO等待事件/多磁盘可以实现同时处理)
- CPU密集型程序:程序中进行大量的数据运算处理,CPU资源足够,则可以同时处理,提高效率(线程数为CPU核心数+1,多出来的一个是当某一线程阻塞时顶替用的。如果创建进程过多,会增加切换调度的成本)