1. 线程概念
线程:轻量级进程,在进程内部执行,是OS调度的基本单位;进程内部线程共用同一个地址空间,同一个页表,以及内存中的代码和数据,这些资源对于线程来说都是共享的资源
进程:在用户视角下,内核数据结构+该进程对应的代码和数据;在内核的视角下,承担分配系统资源的基本实体
其实在之前没有了解线程之前的进程,就是一个只有一个主线程的进程
现在又该如何理解线程和进程之间的关系呢?
线程和进程之间就像家庭成员和家庭之间的概念,家庭是由所有家庭成员共同组成的,在这个社会中可能有三口之家,五口之家
我们在社会中被描述为一个整体,比如户口本就是按家庭发放的,房屋是按家庭建造的,社会资源按家庭分配的,例如疫情期间买菜
家庭成员和家庭之间的关系就是一荣俱荣,一损俱损的关系(线程异常时会触发信号机制,终止进程,内核所有线程都会退出)
我们在家庭中扮演不同的角色,也在使用不同的资源,家庭负责分配这些资源,其中有大部分资源是家庭成员之间共享的,比如卫生间,客厅,但总有一个房间是给你住的,作为你的私人空间
家庭资源:空间,数据
私人空间:后面会说
在Linux中,没有专门为线程管理,创建新的数据结构,而是沿用了进程的task_struct,用它来模拟线程,线程和进程有很多共性,为此Linux下的所有版本都安装了pthread系统库,为了提供用户使用的接口
库底层调用了clone系统接口,所以系统提供一部分,库提供一部分,就组成了Linux下的线程
所以使用线程库的时候,需要包含头文件<pthread.h>,编译时需要-lpthread
线程共享进程数据,但也拥有自己的一部分数据
线程独有:
- 线程ID
- 一组寄存器(上下文)
- 独立栈结构
- errno变量在线程内部
- 信号屏蔽字(block)
- 调度优先级
线程共有:
- 文件描述符表
- 信号处理方式
- 当前工作目录
- 用户id和组id(权限)
线程独立的栈结构(保存临时数据)和上下文数据,体现了线程的动态属性
线程如何实现独立的栈结构:
线程库提供了线程创建接口,它会在地址空间的共享区中创建对应线程的栈结构,其实在上面系统接口中就有所体现clone中有一个参数child_stack的指针,栈地址,栈的组成应该是系统提供的
通过clone系统接口的第一个参数函数指针,其实如何让线程执行自己代码,其实就是执行函数代码
2. 线程vs进程
进程是资源分配的基本单位
线程是CPU调度的基本单位
线程切换的成本更低
因为线程间共享地址空间和页表,这些不需要切换
其次,CPU内部有L1~L3 的 cache 高速缓存(对内存的代码和数据根据局部性原理,预读到CPU内部,进而提高效率)也不用切换
3. 线程的优缺点
优点:
- 创建,切换,占用资源都比进程小
- 能充分利用多处理器可并行的数量
- 在等待慢速IO操作结束的同时,程序可以执行其他任务
- 计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中
- IO密集型应用,为了提高性能,将IO操作重叠,可以同时等待不同的IO
缺点:
缺乏访问控制(后续会学互斥,同步,信号量来解决这一问题)
完。