内核与资源角度:
进程=分配系统资源的基本实体。
线程=CUP调度的基本单位。
初步理解线程:
在之前我们讲过,进程=PCB(task_struct)+代码和数据,如上图所示。
而线程是什么呢?
线程是进程的一个个分支!一个线程 = 一个PCB+一份自己需要执行的代码和数据!不同的线程执行进程中不同的代码,各司其职。
一个线程执行一部分代码,多个线程同时执行,让进程整体效率提升!
而我们之前所讲的进程其实是:内部只有一个线程的进程!(单线程)
结论:
1.线程也采用PCB结构体来描述的
2.对资源的划分,本质是对虚拟地址的划分。也就是说,虚拟地址就是资源的代表。
3线程对进程代码的“划分”,不需要我们人为的去“划分”!因为进程所要执行的代码,其本质都是由一个个函数组成的!这本就是天然的“划分”好了的状态,所以线程对函数“划分”即可(获得函数的入口地址即可)!
4.线程其实不会对资源进行划分,进程内的大部分资源都是共享的,不存在说这个资源是线程a的谁都不可以访问!对代码的“划分”也不是真正的划分,仅仅是表示对任务的分配。一个线程负责执行一部分代码,让进程的代码同时被多个线程推进!
5.Linux的线程就是轻量级的进程(单线程进程)!
6.进程强调独占,部分共享(如进程间的通信)
线程强调共享,部分独占
补充:
windows下的线程设计,与Linux的并不相同!Linux的线程都是使用PCB结构体描述的,但是windows下的线程是采用新设计的结构体:TCB来描述的。
越复杂的代码可维护性、健壮性越不好,所以Linux在这一方面采用复用的方式,设计的更好!
分页式存储管理
进一步理解线程:内核资源的划分
物理内存管理
物理内存最小管理与分配单位:页框/页帧,大小为4KB。当然虚拟内存是与物理内存一一对应的,虚拟内存也是以4KB为基本单位进行分配(是分配噢,不是读写)。
之前我们在文件系统中也讲过:磁盘数据的分配读写(磁盘是例外),是以4KB为单位进行的。【Linux系统】详解Ext2,文件系统-CSDN博客
虚拟页面(4KB) ↔ 物理页框(4KB) ↔ 磁盘块(4KB)
当然不是真的划分为一个个4KB的空间,实际上是一个整体,只是OS在逻辑上进行了划分。
OS采用结构体:page,进行描述!
page描述了页框的各种信号,其中包含了页框的状态:是否被使用,是否被锁定等等。
并采用数组:struct page mem[1048576],进行组织!
所以每一个page都会对应一个数组下标!而我们让数组下标 * 4KB就可以得到page的起始首物理地址了!
起始首地址+页框中的偏移量=真实的物理地址。
有了以上的梳理,我可以知道,当线程或进程申请物理内存时:
1.查数组,修改page 2.建立page与内核数据结构的映射关系
页表
重新认识页表
在此之前,我们认识页表就如图所示:一张表保存虚拟地址与物理地址映射关系。
思考一个问题:
如果一张页表将虚拟地址与物理地址的映射关系全部保存,(以32位机器为例)一个地址是4字节,那么页表中一排就要保存8字节数据。那么一共有多少地址需要我们保存呢?4GB!这也就意味着页表的大小将会来到:8字节 * 4GB = 32GB!这是不现实的!所以页表是绝不可能仅用一张表来保存映射关系的。
页表真正的保存方式:
真正的页表由两部分组成:页目录、页表。
虚拟地址的转化:
首先将一个虚拟地址划分位3部分:以10位、10位、12位为3组(32位下)
前10位:表示指向页目录的地址,其中页目录中保存的是页表的地址。
中间10位:表示指向页表的地址,其中页表中保存的是页地址(起始地址)。
最后12位:表示页中的偏移量,前面的地址找到了具体的页框,最后加上偏移量,就得到了真正的物理地址了!