一,引言

本章主要带大家了解,在具体的Linux中线程是如何被实现的,以及通过具体的操作系统(Linux)来理解线程的主要作用特点如何实现,和进程之间的关系。

二,什么是线程

在Linux操作系统中,线程就是一个进程的执行流。在之前学习进程时,进程包括内核数据结构以及所对应的数据和代码。内核数据结构主要以PCB;在Linux中也就是(task_struct)结构体为代表。通常来说都是一个进程只有(task_struct)结构体。如下图:

但是实际上来说,一个进程并不是只有一个task_struct。而是有多个task_struct。它们分别指向同一个虚拟内存空间,但是指向不同的代码数据段。如下图:

因此,这一个个的task_struct有相同的虚拟地址空间可以看到相同的数据。所有这一个个的执行流就叫做线程。在Linux内核中叫做--轻量级进程。用户层面叫做(线程)。在Linux操作系统中,线程本质就是使用轻量级进程来模拟实现的。

本质上就是通过不同的虚拟地址空间的地址来定位不同的资源。在之前学习的ELF文件中,要执行的代码会按照顺序进行编码,从小到大的顺序。之后通过页表来定位到物理内存,页表定位的原理如下:

1,内核资源划分

在物理内存和磁盘之间大体是通过特定的大小进行IO输入和输出的。因此对于物理内存也并不是一整块的物理内存而是化成一块一块的小内存块。下文都以4kb为例子,如下图:

这么多的内存块都需要操作系统进行管理,因此每一块的内存块都有描述该内存块的结构体,通过相对应的数据结构对这些内存块的管理。最终就实现了对物理内存的管理。在了解物理内存的结构之后,那么是页表是如何实现相对于的关系呢?

以32位操作系统为例,虚拟内存共有32位:0000 0000 0000 0000 0000 0000 0000 0000

其中前十位代表页目录,中间十位代表页表,最后十二位代表物理内存的偏移量。如下图:

因此第一步,通过前十位找到是属于页目录对于的页表,之后根据中间十位找到对应的页的地址找对对应的物理内存地址。最后根据最后十二位找到所属的具体的字节数据。这个过程本质上会交给CPU中MMU中去执行,上图中页目录的地址会寄存在CPU的CR3寄存器中。

本质上申请内存只会提供对应的虚拟地址,只有在使用时,通过缺页中断等等,差对应数组的表看物理内存中哪一个没有被占用,通过修改page表(上述管理物理内存的结构体),与之相对于的有了page表也就知道了物理地址,将该物理地址填充到对应的页表下,就实现了物理地址与虚拟地址的映射关系。

三,进程与线程的对比

首先与进程相比创造一个新的线程要比进程代价小很多,其次在进行调度的过程中操作系统要处理的事务相比进程也要小很多。需要注意的时,在进行进程切换时,会切换虚拟地址空间,而虚拟地址空间的切换会扰乱虚拟器的缓存机制。在操作系统进行进程的切换中页表缓存TLB和硬件cache会直接失效。线程虽然是共享资源的,但是有一部分是独占的(最主要的是栈,寄存器以及上下文数据)。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐