线程概念
线程是程序里的一个执行路线。
一切进程至少都有一个执行线程
线程在进程内部执行,本质是在进程地址空间内运行
分页式存储管理
虚拟地址和页表的由来
西靠一下,如果在没有虚拟内存和分页机制的情况下,每一个用户程序在物理内存上对应的空间必须是连续的每个程序的代码和数据长度不同,按照这样的映射方式,物理内存将会被分割成各种离散的块
运行一段时间后,他们占据的物理内存空间可以被回收
我们希望操作系统一共给用户的空间必须是连续的,但是物理内存不要连续物理内存按照一个固定的长度的页框进行分割,有时叫做物理页,每个页框包含一个物理页,一个页大小等于页框的大小
物理内存管理
页框的大小会被划分,但是物理页很多,操作系统会进行管理,持续监控
struct page结构是操作系统的每个物理页,为了节省内存,使用了大量的联合体
页表
页表中的每一个表项,指向一个物理页的开始地址,在32位系统种,虚拟内存的最大空间是4g
虽然最后使用的物理内存是离散的,但是与虚拟内存对应的线性地址是连续的
页目录结构
每一个页框都被一个页表中的一个表项来指向了,这个1024个页表也需要被管理起来
单级⻚表对连续内存要求⾼,于是引⼊了多级⻚表,但是多级⻚表也是⼀把双
刃剑,在减少连续存储要求且减少存储空间的同时降低了查询效率
缺页异常
设想,CPU给MMU的虚拟地址,在 TLB 和⻚表都没有找到对应的物理⻚,该怎么办呢?其实这就是
缺⻚异常 Page Fault ,它是⼀个由硬件中断触发的可以由软件逻辑纠正的错误。
假如⽬标内存⻚在物理内存中没有对应的物理⻚或者存在但⽆对应权限,CPU就⽆法获取数据,这种
情况下CPU就会报告⼀个缺⻚错误。
由于CPU没有数据就⽆法进⾏计算,CPU罢⼯了⽤⼾进程也就出现了缺⻚中断,进程会从⽤⼾态切换
到内核态,并将缺⻚中断交给内核的Page Fault Handler 处理
线程的优点
创建新线程的代价比新进程小
线程占用资源更少
能充分利用多处理器的可并行数量
线程的缺点
性能损失,健壮性降低,缺乏访问控制,编程难度高
线程异常
单个线程出现问题,野指针问题会导致线程崩溃,进程也会崩溃
线程用途:能提高IO密集型程序的用户体验,
Linux进程vs线程
进程间具有独立性,线程共享地址空间,也就是共享进程资源
进程和线程:进程是资源分配的基本单位,线程是调度的基本单位
Linux线程控制
POSIX线程库
头文<pthread.h>
链接这些线程函数库时要使用编译器命令的“-lpthread.h”
创建线程
功能:创建⼀个新的线程 原型: int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);参数: thread:返回线程ID attr:设置线程的属性,attr为NULL表⽰使⽤默认属性 start_routine:是个函数地址,线程启动后要执⾏的函数 arg:传给线程启动函数的参数 返回值:成功返回0;失败返回错误码线程停止
线程函数return 这种方法对主线程不适用,从main函数return相当调用exit
线程可以调用pthread_exit终止自己
线程等待:已经退出的线程,其空间没有被释放,仍然在进程的地址空间内。
• 创建新的线程不会复⽤刚才退出线程的地址空间。
分离线程
默认情况下,新创建的线程是joinable的,线程退出后,需要对进行pthread_join操作,否则无法释放资源,从而造成系统泄露
int pthread_detach(pthread_t thread);线程ID及进程地址空间布局
pthread_create函数会产生一个线程ID,存放第一个参数指向的地址中,该线程ID和前面说的线程ID不是一回事
pthread_create函数第⼀个参数指向⼀个虚拟内存单元,该内存单元的地址即为新创建线程的线程ID,属于NPTL线程库的范畴。线程库的后续操作,就是根据该线程ID来操作线程的