【操纵系统---Linux】一文带你入门相识线程和假造地点空间中页表映射的秘密 ...

打印 上一主题 下一主题

主题 823|帖子 823|积分 2484

绪论​

逐日鼓励:“努力去做自己该做的,但是不要期待回报,不是付出了就会有回报的,做了就不要后悔,不做才后悔。—Jack”
    绪论​:
本章是LInux中非常告急的线程部分,通过相识线程的基本概念:线程到底是什么、进程和线程的关系、线程为什么叫轻量级进程、为什么要用线程(他的比较与进程的长处)…;当我们相识完线程后此次对假造地点空间进一步认识,它此中的一些细节页表到底是如何映射的找到物理内存中的正确位置的,后续还将持续更新Linux线程的更多知识,敬请期待~
————————
早关注不迷路,话不多说安全带系好,发车啦(发起电脑观看)。

  1.线程的概念

   

  • 线程是比进程更加轻量化的一种执行流
  • 线程是在进程内部执行的一种执行流
  • 线程是CPU调理的基本单元 / 进程是负担系统资源的基本实体
  1.1解释线程的概念:



  • 在Linux下线程本质就是进程,因为他们共用一套数据结构,线程不一样的是他并不用再次的申请资源,多线程和第一个创建的线程共用同一块资源(上图中线程都指向同一块地点空间!
  • TCB(Thread线程)结构体,线程的实现差别的平台不一样,Windows就单独实现了TCB,而Linux中线程的实现的TCB是复用了PCB(Process进程)的,Linux这是为了防止冗余(还要单独的实现一份TCP的数据结构以及系统调用的消耗)
  • 线程是比进程更加轻量化的一种执行流:因为创建一个进程的本钱是比较大的(地点空间,页表,状态设置,io的创建各种数据结构),而线程他们共用同一份资源(同一份地点空间),也就是不用再次创建各种数据结构和申请各种资源的,所以称他是轻量化的
  • 线程长处及原理:将原本一个进程完成的工作分成多份,各个线程分工的来完成各自部分,最终全部完成,所以线程在地点空间间运行。
  • 线程(本质是)差别于进程(进程 = 内核数据结构pcb + 数据和代码),现在它由多个执行流(多个pcb)构成,所以我们可以把这种线程称为轻量级进程,因为其一个线程并不能代表整个进程,整个进程为上图蓝色框内的所有构成(差别于之前的是他由多个执行流 + 数据和代码构成)。
  • Linux中TCB和PCB是一样,所以CPU并不用区分PCB和TCB,并且CPU拿到的其实是TCP中的LWP(后面会细说,先相识)而非线程中PCB的PID来 找到每个轻量级进程(PCB本质就是单独只有一个进程,它能理解为只有一个执行流的线程,此中第一个执行流被称为主线程,他的LWP和PID是一样的,所以就表现我们之前学的其实也没错,通过PID也能控制各个进程(因为虽然CPU控制的是LWP,但一个进程只有一个线程它的LWP就和PID雷同,所以是一样的概念))。
  • 线程是CPU调理的基本单元 / 进程是负担系统资源的基本实体:因为进程是分成多份的一份份线程,故CPU的调理时就会一份份的调理;进程团体能通过进程地点空间和页表找到所需的资源所以有进程是负担系统资源的基本实体。
  • 一个进程里的多个执行流(就是线程),此中每个线程的pid是雷同的
  • 虽然线程TCB是进程TCP的一部分(相当于共用一个),但注意的时每个线程都有属于自己的TCB
可以想象成理解成:相当于社会上,都是以每个家庭为单元(一个个进程),每个家庭都有多个成员(相当于线程),并且所有家庭成员的工作都是为了总体(一个目的),只有当我们每个家庭成员都做好对应的事(每个线程做好事),才气让家庭过好(进程正常执行)。(而之前的进程相当于一个家庭只有一口人)
1.2 线程是属于一个进程的多个执行流:

线程是属于一个进程的多个执行流之一,所以他们的pid是雷同的
验证:
原理通过函数pthread_create()创建线程,查看他们pid是否雷同即可
  1. #include<pthread.h>
  2. //新线程
  3. void *ThreadRoutine(void* arg)
  4. {
  5.     const char* threadname = (const char*)arg;
  6.     while(true)
  7.     {
  8.         cout << "I am a new thread" << threadname << ", pid:" << getpid() << endl;
  9.         sleep(1);
  10.     }
  11. }
  12. int main()
  13. {
  14.     //执行线程前已经有进程了!
  15.     pthread_t tid;
  16.     //创建线程并执行ThreadRoutine函数,后面的是传进去的参数
  17.     pthread_create(&tid,nullptr,ThreadRoutine,(void*)"thread 1");
  18.     //thread 线程tid,atttr 设置的线程属性,
  19.     //start_routine 函数指针(传一个函数)
  20.     //arg前面函数指针的参数
  21.     //主线程,线程执行的同时 主线程会继续往后执行!
  22.     while(true)
  23.     {
  24.         cout << "I am main thread" << ", pid:" << getpid()<< endl;
  25.         sleep(1);
  26.     }
  27.     return 0;
  28. }
复制代码
他们的pid雷同,并且用ps ajx查看也进程也只有一个,所以就证实了他们是在同一个进程中的差别线程。

查看指定进程指令
  1. ps ajx | grep process
复制代码
查看进程并过滤出含process的进程,发现确实只有一个进程在运行:

查看所有轻量级进程指令:
  1. ps -aL(all light)
复制代码
查看发现此时有两个线程,也就对应了一个主线程和一个刚创建的新线程:

   LWP:Light Weight Processes也就是轻量级进程,他就像进程的PID一样来区别差别线程!
CPU调理时本质看的是LWP(而不是PID),此中主线程他的PID = LWP,所以上图的第一个线程就是主线程
  
总结:
线程的概念,本质就是CPU调理的基本单元Linux内核复用了进程PCB,模拟充当线程,让线程可以复用进程的代码。Linux中所有的执行流全部叫做轻量级进程。若要谈进程那就不能只谈pcb还有进程地点空间和页表,谈执行流那就都是轻量级进程,当进程内只有一个执行流就是进程,若有多个执行流就是线程,此中每个线程指向同一个地点空间让数据资源共享,并且通过分别代码(函数pthread_create(…))给到各个线程来执行差别代码。

1.3 线程比进程更轻量化


  • 从CPU调理上看

    • 线程间切换:地点空间和页表(会有寄存器存着他们的位置,指向他们)不用切换,只用切换产生的临时数据的寄存器。
    • 进程切换:所有寄存器都要切换,页表,上下文保存,…。

  • 从线程上看

    • CPU内有硬件级别的cache缓存,他的作用是把正在执行的代码的附近代码先缓存进cache中,原因一样平常数据正在访问某一行代码,此时较大可能会访问这一行附近的代码(称为局部性原理),所以会把附近的代码先缓存进cache(预加载),方便后续继承用,把存在cache中的代码/数据叫做热数据。
    • 线程切换时就不用切换cache(里面的数据可能还有用)
    • 进程间就要切换cache(一个进程的代码对另外一个进程偶然义)


   所以线程切换服从高是因为:
  

  • 切换寄存器少
  • 不用更新cache
  假如一个进程的分配10ms的时间片,此时线程会瓜分这些时间片(时间片也是资源)
因为每个线程都分配了一定的时间片,所以调理时当把这些线程的时间片都用完后才算进程调理完。
1.4 线程的长处:


  • 创建、调理、释放量级比进程轻。
  • 创建本钱低
  • 并行进行多种任务的处置惩罚处置惩罚(进程也有)
附:
   进程分为:
  

  • 盘算麋集型应用(盘算分为多份)
  • IO麋集型应用(下载时多线程下载)
  1.5 线程的缺点:


  • 线程的切换:性能损失
  • 健壮性降低(鲁棒性):多线程步伐,当一个线程崩溃会导致全部线程都崩溃(就好比一个团队一人做的事变就相当于整个团队的事变)
  • 缺乏访问控制:线程间的资源可能会因为共享而出现题目
1.6 线程的用途:


  • 合理的利用多线程,能提高CPU麋集型步伐的执行服从
  • 合理的利用多线程,能提高IO麋集型步伐的用户体验(如生活中我们一边写代码一边下载开辟工具,就是多线程运行的一种表现)
1.7 TCP和PCB的关系

线程除了地点空间共享外还有共享:

  • 文件描述符
  • 每种信号的处置惩罚方式(handler,每个线程有独立的tcb,但block和pending不是私有的)
  • cwd表现当前所在目次的字符串(进程启动时tcb会记录)
线程他也有自己的私有成员:

  • 线程ID(LWP)
  • 调理优先级(每个线程被单独调用)
  • 一组寄存器:线程有独立的上下文数据(动态切换)
  • 独立的栈结构(函数中,动态运行)
2.重谈地点空间(假造地点 ->物理地点)

回首之前文件系统IO他的基本单元(最小单元)巨细:4kb(文件块)
操纵系统文件系统 维护和管理 磁盘打开与加载文件到物理内存中运行。


  • 物理内存和磁盘进行交互的基本单元是4kb,所以文件系统上看到的可执行步伐内的数据都是一块块的4kb,对此物理内存上也是分成了一块块4kb的段,他们就像杯子与盒子必须巨细适配,此中物理内存所分成的一块块数据称为页框,而可执行步伐的称为页帧,所以物理内存分成的块和文件块都指定是4kb。
  • 物理内存中其实是有无数个小的存储01的高低硬件电路,用来通过充放电的方式来存储或删除数据(但他的条件是有电,当掉电他就会丢失内存里的数据)。
  • 一个页框的巨细为4kb,那就会有32个INode文件(一个INode文件巨细为128byte,1024 * 4 / 128 = 32)
  • 物理内存的空间是4GB时会有1048,576(102410241024 * 4 / 4*1024)个页框
   此中这里有点混乱,但只需要你始终保持区分 物理内存(页框)磁盘空间(页帧) 即可更好的理解
  而这些直接分出来的一块块数据区域(页框,页帧):
页框可以描述成结构体:
  1. struct  page
  2. {
  3.     //描述page的使用情况 int flag; 定义宏来描述其是否使用:#define unuse 0x1
  4.     //page的属性
  5. }
复制代码
通过一个数组的形式来进行管理,这样形成一个数组,这样对内存的管理,就酿成了对数组的管理。
  1. struct page pages[1048576]
复制代码

2.1页表的原理

   页表的作用是用于将假造地点空间通过映射找到真正在物理内存上的空间的,之前我们把页表想象成一张类似哈希表的结构,左边是假造地点右边映射物理地点,但是现实我们算算就发现是不可的,一个页表存在两个地点那就8byte在加上一些标记位那么就算一行(组)是10byte,而我们32位机上会有2^32个地点,那么页表就需要有2 ^ 32个行每一行是10字节,那么一个页表就非常的大了,所以他是不完善不合理的。
  对此页表存的假造地点其实是是分比特位来利用的,此中前20位用来找到正确的物理地点中的页框
此中20位又分成

  • 前10位 对应着页目次:存着页表项数组下标(用于从页框结构数组中找到正确的位置)
  • 后10位 对应着页表项:存的就是页框的起始地
  • 页目次、页表项本质它们都是数组
  • 后12位用来找到页框中的准确位置(相当于找到了页框后地点需要确定偏移量找到具体位置)(12位 = 2 ^ 2 * 2 ^ 10 = 4kb,因为刚好是4kb所以就能找到页框中的所有数据)
  • 设计成这样我们前20位所找到的页框(4kb),而非字节这样就能很大的缩小了所要的空间。

    所以假造地点 -> 物理地点:前20比特位找到数据所在页框的起始地点 + 后12个比特位找到数据具体地点
页表中的标记位(物理地点旁边的3列)



  • 访问期间若发现目标资源不在内存,则会触发缺页中断,再次进行内存的分配,并建立新映射。
  • U/K权限:U表现当前是User用户态,K表现当前是Kernel内核态。

本章完。预知后事如何,暂听下回分解。
假如有任何题目欢迎讨论哈!
假如觉得这篇文章对你有所帮助的话点点赞吧!
持续更新大量Linux细致内容,早关注不迷路。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

大连全瓷种植牙齿制作中心

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表