绪论

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

1.线程的概念
1.1解释线程的概念:

可以想象成理解成:相当于社会上,都是以每个家庭为单位(一个个进程),每个家庭都有多个成员(相当于线程),并且所有家庭成员的工作都是为了总体(一个目的),只有当我们每个家庭成员都做好对应的事(每个线程做好事),才能让家庭过好(进程正常执行)。(而之前的进程相当于一个家庭只有一口人)
1.2 线程是属于一个进程的多个执行流:
原理:
通过函数pthread_create()创建线程,查看他们pid是否相同即可
#include<pthread.h>
//新线程
void *ThreadRoutine(void* arg)
{
const char* threadname = (const char*)arg;
while(true)
{
cout << "I am a new thread" << threadname << ", pid:" << getpid() << endl;
sleep(1);
}
}
int main()
{
//执行线程前已经有进程了!
pthread_t tid;
//创建线程并执行ThreadRoutine函数,后面的是传进去的参数
pthread_create(&tid,nullptr,ThreadRoutine,(void*)"thread 1");
//thread 线程tid,atttr 设置的线程属性,
//start_routine 函数指针(传一个函数)
//arg前面函数指针的参数
//主线程,线程执行的同时 主线程会继续往后执行!
while(true)
{
cout << "I am main thread" << ", pid:" << getpid()<< endl;
sleep(1);
}
return 0;
}
他们的pid相同,并且用ps ajx查看也进程也只有一个,所以就证明了他们是在同一个进程中的不同线程。

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

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

LWP:Light Weight Processes也就是轻量级进程,他就像进程的PID一样来区别不同线程!
CPU调度时本质看的是LWP(而不是PID),其中主线程他的PID = LWP,所以上图的第一个线程就是主线程
总结:
线程是CPU调度的基本单位,在Linux内核中它的结构复用了进程PCB,让线程复用进程的代码,所以多线程共用一个资源。Linux中所有的线程又叫做轻量级进程。若要谈进程那就不能只谈pcb还有进程地址空间和页表,谈执行流那就都是轻量级进程(线程),当进程内只有一个执行流就是进程,若有多个执行流就是线程,其中每个线程指向同一个地址空间让数据资源共享,并且通过划分代码给到各个线程来执行不同代码。
1.3 线程比进程更轻量化

所以线程切换效率高是因为:
假如一个进程的分配10ms的时间片,此时线程会瓜分这些时间片(时间片也是资源)
因为每个线程都分配了一定的时间片,所以调度时当把这些线程的时间片都用完后才算进程调度完。
1.4 线程的优点:
附:
进程分为:
1.5 线程的缺点:
1.6 线程的用途:
1.7 TCP和PCB的关系
线程除了地址空间共享外还有共享:
线程他也有自己的私有成员:
2.重谈地址空间(虚拟地址 ->物理地址)
回顾之前文件系统IO他的基本单位(最小单位)大小:4kb(文件块)
操作系统文件系统 维护和管理 磁盘打开与加载文件到物理内存中运行。

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

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

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

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



