页表与线程学习

线程

线程(TCB)是进程(PCB)的基本单位。
linux认为没有进程,没有线程在概念上的区分,只有一个叫做执行流。这句话指明了都是PCB。
Linux的线程是用进程(PCB)模拟的.
这样做的好处

  1. 不用在单独设计TCB。
  2. 不用维护TCB和PCB之间的关系。
  3. 不用单独编写任何调度算法。
    CPU看到的所以task_struct都是一个进程
    CPU看到的所以task_struct都是一个执行流(线程)

进程 = 内核数据结构 + 进程对应的代码和数据
进程 = 内核视角 :承担分配系统资源的基本实体(进程的基座属性)
进程向系统申请资源的基本单位。
内部只有一个执行流的进程 — 单执行流进程。
内部有多个执行流的进程 — 多执行流进程。

使用第三方库得加上
l库名才能进行编译
页表与线程学习_第1张图片
ps axj//查进程用的
查线程 ps -al //a表示all ,l表示轻量级进程。

页表

页表结构:页表跟书一样有页目录,页目录下有页表。而每个页目录又分配有几个字节的地址。每块地址对应的页表又有的32次方个字节。
页表在物理内存中一块单位是KB。4KB里面的数据我们叫页框(Page为单位)。这4KB是虚拟地址编译划分好的。
把磁盘划分的区域叫页帧。

IO的基本单位是块 – 4KB
通过页表查找对应的page在通过虚拟地址的后12位的4KB查找到页内偏移量找到2的12次方覆盖页内的所以地址。

这样设置页表有啥好处:
1.进程训地址管理和内存管理,通过页表+page进行解耦
2.分页机制+按序创建页表 = 节省空间。

如何使用线程

原生线程库 pthread
syscall
pthread_self获取 进程id
pthread_exit终止进程还有个就是pthread_cancel(线程被取消)也和exit一样都是退出。
在这里插入图片描述> 等待退出的线程使用pthread_join函数 > retval为线程退出时的退出码。 在这里插入图片描述

线程异常了,进程也会异常 。

1️⃣ 线程知识点总结:

各个线程都要各自的栈区,但是它们的堆区是共用的。
进程是资源分配的基本单位,线程是调度的基本单位。
用户态线程的切换在用户态实现,不需要内核支持。
使用多线程可以更加充分利用cpu资源,使任务处理效率更高,进而提高程序响应。
对于多核心cpu来说,每个核心都有一套独立的寄存器用于进行程序处理,因此可以同时将多个执行流的信息加载到不同核心上并行运行,充分利用cpu资源提高处理效率。线程包含cpu现场,但是线程只是进程中的一个执行流,执行的是程序中的一个片段代码,多个线程完整整体程序的运行
每个线程在进程虚拟地址空间中会分配拥有相对独立的栈空间,而并不是共享栈空间,这样会导致运行时栈混乱。
进程比线程安全的原因是每个进程有独立的虚拟地址空间,有自己独有的数据,具有独立性,不会数据共享这个太过宽泛与片面。
进程有独立的地址空间,但是同一个进程的线程之间共享同一个地址空间。
线程并没有独立的虚拟地址空间,只是在进程虚拟地址空间中拥有相对独立的一块空间。
其实不仅仅是内存隔离的问题,还有就是异常针对的是整个进程,因此单个线程的崩溃会导致异常针对进程触发,最终退出整个进程。
大量的计算使用多进程和多线程都可以实现并行/并发处理,而线程的资源消耗小于多进程,而稳定向较多进程有所不如,因此还要看具体更加细致的需求场景。
因为线程之间共享了进程中的大部分资源,因此共享的数据不需要重新创建或销毁,因此消耗上低于进程,反之也就是速度快于进程。
因为线程之间共享地址空间,因此通信更加方便,全局数据以及函数传参都可以实现,而进程间则需要系统调用来完成。
程序是静态的,不涉及进程,进程是程序运行时的实体,是一次程序的运行。
进程是资源的分配单位,所以线程并不拥有系统资源,而是共享使用进程的资源,进程的资源由系统进行分配。
任何一个线程都可以创建或撤销另一个线程。
进程因为每个都有独立的虚拟地址空间,因此通信麻烦,需要调用内核接口实现。而线程间共用同一个虚拟地址空间,通过全局变量以及传参就可实现通信,因此更加灵活方便。
线程拥有自己的栈空间且共享数据没错,但是资源消耗更小,且便于进程内线程间的资源管理和保护,否则会造成栈混乱。

线程独立的栈结构:

页表与线程学习_第2张图片
在os中没有所谓的线程只有轻量级进程,但用户所需要的是线程。所以操作系统出了个libthread.so的库。让用户通过该库来调用轻量级进程,给用户使用被OS包装过的轻量级进程。

如何将共享变量变成线程局部存储。
在这里插入图片描述
在前面加上__thread就变成了线程私有的全局变量。__thread会将变量拷贝给每个线程。
通过syscall来获取线程的tid。
在这里插入图片描述

线程分离(pthread_detach)

pthread_join
1、线程退出释放资源用。
2、获取线程对应的退出码。
我们如果不关心线程的返回值(2),对于join就不是最好的选择。pthread_detach就是比较好的选择。它只有上面第1点,一个线程不能即join又分离。

exit与pthread_exit的区别

exit是进程退出,pthread_exit是线程退出。
任何一个线程调用exit,都表示整个进程退出。

线程的互斥

三个概念:
1、临界资源 ----------多个执行流都能看到并访问的资源。
2、临界区 ---------多个执行流,代码中,有不同的代码,但是访问临界资源的代码,我们称之为临界区。

关于线程互斥我们举个例子我们进行购票的时候,比方有100张票,tickets=100;在内存里面是100,我们买了一张后cpu获取内存的tickets进程通过寄存器进行–计算变成了99,在返回给内存并把内存的tickets改成99;但我们多个线程同时进行的时候寄存器。

mutex简单理解就是一个0/1的计数器,用于标记资源访问状态:0表示已经有执行流加锁成功,资源处于不可访问,1表示未加锁,资源可访问。
主线程调用pthread_cancel(pthread_self())函数来退出自己, 则主线程对应的轻量级进程状态变更成为Z, 其他线程不受影响,这是正确的(正常情况下我们也不会这么做…)
主线程调用pthread_exit只是退出主线程,并不会导致进程的退出
pthread_self() 用于获取用户态线程的tid,而并非轻量级进程ID

有趣带锁跑路。

线程加锁和解锁具有原子性

线程加锁本质:是将数据从内存读入寄存器,将数据从共享变成线程私有。
该过程我们举个例子,比方线程A先使用寄存器进行数据运算,但此时线程B过来了让它走,线程A就带着上下文和锁走了,mutex的值也在上下文此时mutex为空。线程B上去了,进行运算与mutex的值交换后发现mutex为空就退出CPU 。此时线程A带着上下文内容回来继续运算,算法与mutex的值交互后返回。

实现:

你可能感兴趣的:(学习,开发语言)