文章目录
-
-
- [1. 如何理解Linux中的线程?](#1. 如何理解Linux中的线程?)
- [2. 重新定义线程和进程](#2. 重新定义线程和进程)
- 3.重谈地址空间---多线程
- [4. Linux线程周边的概念](#4. Linux线程周边的概念)
-
- [4.1 线程的优点](#4.1 线程的优点)
- [4.2 线程的缺点](#4.2 线程的缺点)
- [4.3 线程异常](#4.3 线程异常)
- [4.4 线程用途](#4.4 线程用途)
- [4.5 线程库中的接口使用](#4.5 线程库中的接口使用)
-
-
序:本章之后,我们对Linux系统部分的知识就到这里结束,这是Linux系统部分的最后一个知识点---多线程!!!本章我们将知道什么是线程,并且重新理解什么是进程,以及Linux下特有的线程,还有线程的优缺点等等
线程:是进程内的一个执行分支。线程的执行粒度要比进程细。
1. 如何理解Linux中的线程?
地址空间是进程的资源窗口(加载动态库、申请内存和定义临时变量等,都要通过地址空间来完成!!!)
进程(1个task_struct,1个地址空间):
进程(多个task_struct,1个地址空间):
问题一:为什么在Linux中,线程在进程"内部"执行,线程在进程的地址空间内运行?
任何执行流要执行,都要有资源,而地址空间就是进程的资源。
问题二:为什么在Linux中,线程的执行粒度要比进程更细?
线程执行进程代码的一部分
2. 重新定义线程和进程
问题一:什么叫做线程?
我们认为,线程是操作系统调度的基本单位!
重新理解进程:内核观点:进程是承担分配系统资源的基本实体。(进程 == 所以的内核数据结构+所以的代码和数据)
问题二:执行流是资源吗?
线程是进程内部的执行流资源!!!
问题三:如何理解我们以前说过的进程?
操作系统以进程为单位,给我们的进程分配资源,我们的进程内部,当前只有一个执行流,以前我们所提到的进程是一个特殊情况,只有一个执行流,现在说的一个进程有多个执行流才是正常!!!

其中既然线程是一种资源,那么线程就要被管理起来------先描述,再组织!!!
Struct tcb(Thread Ctrl Block)在大多数操作系统中,都有对应的PCB结构体(很复杂,但又不得不这样做,还不好维护)
而在Linux中,线程直接复用进程数据结构和管理算法,struct task_struct---模拟进程
Linux没有真正意义上的线程,而是用进程的内核数据结构模拟的线程
CPU无法识别Linux中的进程和线程
线程<=执行流<=进程
Linux中的执行流:轻量型进程
3.重谈地址空间---多线程
如图:
CPU中有个CR3寄存器,其中存的就是页表的页目录地址,也有寄存器存储的是进程控制块的地址
问题一:虚拟地址是如何转换到物理地址的?(32位虚拟地址为例)
其中32位虚拟地址并非一个整体,而是分为了三个部分32=10+10+12。而页表也不是一张表那么简单!!!
32 = 10 + 10 + 12,通过前20位,就已经知道页框的起始位置了。
页框的起始位置 + 虚拟地址最后12位(你要访问的物理内存在页框中的偏移量) = 物理地址中的数据
所以创建一个进程依旧是一个很重的工作。
所以至此以后,我们知道了虚拟地址是如何映射物理地址的,那么访问任何变量都是起始地址+类型 == 页框的起始地址 + 偏移量。
问题一:如何理解资源分配给线程?
线程目前分配资源,本质就是分配地址空间的范围。
4. Linux线程周边的概念
线程vs进程
问题一:为什么线程比进程要更加轻量化?
1. 创建和释放更加轻量化(生死)
2. 切换更加轻量化(运行)
所以线程的整个生命周期都比进程要更加轻量化

4.1 线程的优点
1.创建一个新线程的代价要比创建一个新进程小得多。
2.与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多。
3.线程占用的资源要比进程少很多。
4.能充分利用多处理器的可并行数量。
5.在等待慢速I/O操作结束的同时,程序可执行其他的计算任务。
6.计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现。
7.I/O密集型应用,为了提高性能,将I/O操作重叠。线程可以同时等待不同的I/O操作。
4.2 线程的缺点
1.性能损失
一个很少被外部事件阻塞的计算密集型线程往往无法与共它线程共享同一个处理器。如果计算密集型线程的数量比可用的处理器多,那么可能会有较大的性能损失,这里的性能损失指的是增加了额外的同步和调度开销,而可用的资源不变。
2.健壮性降低
编写多线程需要更全面更深入的考虑,在一个多线程程序里,因时间分配上的细微偏差或者因共享了不该共享的变量而造成不良影响的可能性是很大的,换句话说线程之间是缺乏保护的。
3.缺乏访问控制
进程是访问控制的基本粒度,在一个线程中调用某些OS函数会对整个进程造成影响。
4.编程难度提高
编写与调试一个多线程程序比单线程程序困难得多
4.3 线程异常
1.单个线程如果出现除零,野指针问题导致线程崩溃,进程也会随着崩溃
2.线程是进程的执行分支,线程出异常,就类似进程出异常,进而触发信号机制,终止进程,进程终止,该进程内的所有线程也就随即退出
4.4 线程用途
1.合理的使用多线程,能提高CPU密集型程序的执行效率
2.合理的使用多线程,能提高IO密集型程序的用户体验(如生活中我们一边写代码一边下载开发工具,就是多线程运行的一种表现)
线程共享进程数据,但也拥有自己的一部分数据:
1. 线程的上下文
2. 单独栈
4.5 线程库中的接口使用
问题一:内核中有没有很明确的线程的概念呢?
没有,只有一个轻量级进程的概念,所以操作系统是不会给我们提供线程的系统调用,只会给我们提供轻量级进程的系统调用!!!
pthread线程库 --- 应用层 ---对轻量级进程接口进行封装,为用户提供直接线程的接口。
pthread:
1. 几乎所有的Linux平台,都是默认自带这个库的!!!
2. Linux中编写多进程代码需要使用第三方pthread库!!!
pthread_create( ):

第一个参数:输出型参数,thread id
第二个参数:线程的属性,平时置nullptr就行。
第三个参数:是一个返回值为void ,参数为void的一个函数指针,其中void*可以接收或返回任意类型。
第四个参数:创建线程成功,新线程回调线程函数的时候,需要的参数。
返回值,成功返回0,失败则返回错误码,不会设置全局变量的错误码!!!
要注意的是,pthread_create不是系统调用。而线程库是一个动态库,所以要想使用该函数就要引入该动态库!!!g++ -o @ ^ -lpthread
ps -aL -L选项就能看到轻量级进程的信息了 ,-a选项是显示全部。
其中LWP是轻量型进程(light weight process)
LWP == PID就是主线程,进程内的任意一个线程被杀掉,默认该进程也会被杀掉。
总结:
本章我们了解了线程的概念,并且重新理解什么是进程,以及Linux下特有的线程,还有线程的优缺点,异常,用途,以及接口的使用等等