【Linux】线程(一)

作者 : admin 本文共2067个字,预计阅读时间需要6分钟 发布时间: 2024-06-16 共1人阅读

谈论之前需要先谈论一些线程的背景知识

其中就有进程地址空间,又是这个让我们又爱又恨的东西。

注意:全篇都是在32位的情况下进行的

目录

  • 背景知识:
    • 地址空间:
      • 内存:
      • 页表:
    • 基于以上理解文件缓冲区与虚拟地址:
      • 文件缓冲区:
      • 虚拟地址:
  • 线程:

背景知识:

地址空间:

说在前边,OS通常分为4个核心模块:执行流管理,文件系统管理,文件管理与IO管理。

在这先要涉及到对内存的管理。

内存:

以下是一张内存与磁盘的形象图。
【Linux】线程(一)插图
在没接触内存管理之前我们通常是认为内存是直接一整块的。
现在我们要知道内存其实不是一整块的,而是分成了一个大数组,数组每个大小4kb!每个4kb叫做页框或页帧。
【Linux】线程(一)插图(1)
当然,这个是可以进行更改的,但是需要将OS重新编译一份出来,另外这个数字是由计算机科学家研究出来的。

我们的这个4KB是不是看着很熟悉呢?
4KB也正是磁盘文件与系统进行IO的基本单位。
在OS中的巧合都是精心设计的~

结论:我们磁盘中的可执行程序也是文件,是文件就有对应的inode。我们磁盘中已经天然的按4kb,比如说我们文件存放自己的数据就在datablock[]中,这个就是以4kb进行划分的,所以在进行磁盘IO时,所谓的加载就是把数据块加载到指定的内存块。


那么现在就有一个问题了:当父子进程共享了一个全局变量int类型,进行写时拷贝时是进行4字节的拷贝还是4kb呢?

答案是4kb,这遵循了一个局部性的原则,当你本行的数据被修改,那么下一行会有90的概率也被修改,避免了太多的拷贝,OS也是很忙的。
所以其实我们C语言malloc4字节其实也是申请了4kb,只是我们只能只用4字节(很粗略的理解)
我们的共享内存所以一般也都是申请4096个字节的整倍数…


那么是怎么进行划分的呢,那么多4kb是如何管理的呢?
比如每个内存块被占用了多少,被谁占用了…

所以需要进行管理。
假设我们是4GB,那么大约是一百万个页框,更准确来说是1048576,每个页框都有自己的使用情况。

【Linux】线程(一)插图(2)

最底层使用数组进行管理起来,每个page都有自己对应的下标–>使用对应的下标×4kb == 页框地址

所以对内存的管理就变为了对数组的增删查改。
那么这个数组大约多大呢?
假设每一份是1byte,那么大约是1mb。
但是实际上一份大约是十几byte。那么就是十几MB就可以管理起来这个数组了。


页表:

真实的页表是什么样子?虚拟地址又是如何转化到物理地址?
在还没有真正接触页表之前,我们通常会这么认为:
【Linux】线程(一)插图(3)
我们先来说一下第二个问题:
我们进行地址的转化是需要与CPU进行配合的。
CPU中接收到虚拟地址+MMU–>物理地址。

再来看一下第二个问题:
我们的虚拟地址有32位,那么每个虚拟地址就有32个比特位。

【Linux】线程(一)插图(4)
其中前十比特位用来索引第一张页表,也就是第一张页表的下标。
【Linux】线程(一)插图(5)
那么第一张页表中存放的是什么?
是第二张页表的地址。

【Linux】线程(一)插图(6)
所以中10位也就是第二张页表的索引(下标咯)。
【Linux】线程(一)插图(7)
那么后12位代表着什么?
我们想到每个页框的大小为4kb->4096字节->[0, 4095],而我们的后12位正好也是[0, 4095],所以我们的低12位就是每个页框的偏移量!
【Linux】线程(一)插图(8)
所以我们页表的本质是进行搜索页框!

这种分配方案叫做二级页表,大大减少了内存。

口说无凭,我们计算一下:

首先第一张页表叫做页目录。
存的是第二张页表的地址。
页目录的大小 = 4字节×1024 = 4kb。

第二张页表叫做页表
页表中存的是page的起始地址,
页表大小 = 4字节 × 1024 × 1024 = 4mb。

所以总大小为4mb + 4kb就是页表了!

何况也是按照拉满的进行计算,实际是 <= 这个大小的。

注意:page这个管理内存的数据结构与页表是相辅相成,
它们之间虽然在逻辑上有间接的联系(都是用来管理物理内存的不同方面),但实际上它们的数据内容和直接操作是分离的。

但是我们现在仍然只能获得一个字节的地址,一个int都4个字节,怎么读取一个int的数据呢?
所以需要类型?
汇编会告诉CPU你的对象类型是什么。

所以现在还差一个问题。
当CPU获得虚拟地址时,MMU可以进行运算找到页框。但是这个过程中我们得有页目录的地址啊,才能进一步的运算,地址怎么获得?
在CR系列的寄存器中。
【Linux】线程(一)插图(9)
CR3就负责存页目录的地址。

基于以上理解文件缓冲区与虚拟地址:

文件缓冲区:

文件缓冲区实际上就是从struct page memory这个数组中挑几个page与struct file进行关联,这就是文件缓冲区,至于怎么关联的是依靠字典树,了解一下即可。

虚拟地址:

我们以正文代码段为例:【Linux】线程(一)插图(10)
我们的正文代码实际上是一段范围,如果有20个函数,那我们就可以将正文分成20部分。
是不是很抽象的感觉,没事,我们来好好的捋一捋。
首先我们知道函数是有地址的,是一批代码的入口地址;函数的每一行也都有地址,而我们的函数都是连续的,且编译是以平坦模式的绝对编址,所以最终每个函数都是一个一个连续的代码块。

那么正文就理所当然的可以拆分为20分,本质就是拆分页表,也就是一种资源。

线程:

那么就来看一看一下官方的线程定义:

在进程内部运行,是CPU调度的基本单位。

果然是十分抽象~

线程与进程实际上是由密不可分的关系

本站无任何商业行为
个人在线分享-虚灵IT资料分享 » 【Linux】线程(一)
E-->