个人主页:chian-ocean
文章专栏-Linux
前言:
在Linux中,线程 是一种轻量级的执行单元,它是进程的一部分。多个线程可以在同一个进程内并行执行任务,通常它们共享该进程的资源,如内存空间、文件描述符等。

线程的概念
线程的基本概念:
- 轻量级进程(LWP): 线程被视为进程中的一个轻量级进程(LWP)。与独立的进程相比,线程创建和销毁的开销较小,因为它们共享相同的内存空间和资源。
- 共享资源 : 线程之间共享大部分进程的资源,比如内存空间(堆、全局变量)、文件描述符等。但每个线程拥有自己的程序计数器(PC) 、寄存器集 和堆栈。
- 并行执行: 多个线程可以并行执行不同的任务。这种并行执行能力特别适合多核处理器,可以提高程序的效率。
- 独立调度: 虽然线程共享进程的资源,它们仍然是独立的执行单元,操作系统调度器会对每个线程进行调度,确保线程按照优先级和资源占用情况执行。
- 线程创建与销毁 : 线程可以由主线程或其他线程创建。通过
pthread_create
函数可以创建新的线程,线程结束时可以通过pthread_exit
或者线程的自然结束来销毁。
分页式管理和储存
-
页表(Page Table) 是操作系统用于管理虚拟内存与物理内存之间映射关系的数据结构。在使用分页存储的系统中,进程的虚拟地址空间被划分为多个固定大小的页面(通常为 4KB),而物理内存被划分为多个固定大小的页框(Page Frame)。页表用于记录每个虚拟页面与物理页框之间的映射关系。
-
分页式存储(Paging)是内存管理的一种方式,主要目的是提高内存的利用率和管理效率。

虚拟地址向物理地址的快速映射(TLB)
它是计算机体系结构中一种用于加速虚拟地址到物理地址转换的硬件缓存,这种设备叫做转换检测缓冲区 (TLD :Translation Lookaside Buffer )又叫相关联储存 或者是快表
例如:

TLB 的工作原理
- TLB 命中(Hit) :
- 当 CPU 访问一个虚拟地址时,TLB 会检查该地址是否已缓存。如果找到映射,操作系统直接返回物理地址,CPU 继续执行指令。
- TLB 未命中(Miss) :
- 如果 TLB 中没有找到对应的映射,CPU 会通过查阅页表来获取虚拟地址的物理地址,并将这个新的映射添加到 TLB 中,以供后续使用。
- TLB 替换算法 :
- 由于 TLB 是有限的,当缓存已满时,操作系统需要使用替换算法来决定哪些映射应被淘汰。常用的替换算法包括 LRU(最近最少使用) 和 FIFO(先进先出) 等。
针对大内存页表(多级页表)
多级页表是操作系统为了高效管理虚拟内存而采用的一种页表结构。它将页表分为多个级别,以优化内存使用并提高系统性能。多级页表的关键目的是减少内存空间的浪费,特别是在虚拟地址空间中,大多数进程只使用虚拟地址的部分区域,而不是整个地址空间。

这是一个多级页表 结构,虚拟地址被分为三个部分:PT1 、PT2 和 页内偏移。它说明了一个二级页表的系统,其中:
- PT1(10 位):用于索引顶级页表。
- PT2(10 位):用于索引二级页表,该页表包含实际映射到物理内存的条目。
- 页内偏移(12 位):指定虚拟页中的具体字节位置,通常对应 4KB 的页面大小。
表明了虚拟地址如何被分解并通过多级页表层次结构进行查找:
- 顶级页表(每个条目对应 4MB 的内存块)由前 10 位(PT1)进行索引。
- 二级页表由接下来的 10 位(PT2)进行索引,该表存储着物理内存页的映射。
- 页内偏移 指明了具体的物理内存位置。
2^12 == 4096byte == 4 Kb
进程和线程的区别
定义:
- 进程:是程序在运行中的一个实例,是资源分配的基本单位。每个进程都有自己的地址空间、内存、文件描述符等资源。进程之间相互独立,进程的创建和销毁需要操作系统进行管理。
- 线程:是进程内部的一个执行单元,是操作系统调度的基本单位。多个线程共享进程的资源,如内存、文件描述符等,但每个线程有自己的寄存器、栈等。

线程的优势
共享内存空间:
- 资源共享: 线程共享同一进程的地址空间,这使得不同线程可以直接访问进程中的数据和资源(如内存、文件描述符等)。相比于进程,每个线程之间的通信成本较低。
- 高效的数据共享: 由于线程共享内存,可以更高效地交换数据,而不需要使用复杂的进程间通信(IPC)机制。

更低的创建和切换开销:
- 线程创建快速: 创建线程的开销比创建进程小得多,因为线程共享进程的资源和内存空间,不需要为每个线程分配独立的内存。
- 上下文切换高效: 线程切换的开销较小,因为线程之间共享地址空间,无需像进程切换时那样保存和恢复独立的内存映像。切换线程时,仅需要保存和恢复寄存器、程序计数器等较少的信息。
进程与线程上下文切换的对比
- 根据分页式管理,进程线程对比线程是优势于进程的。
特点 | 进程上下文切换 | 线程上下文切换 |
---|---|---|
内存切换 | 需要切换虚拟内存地址空间(页表) | 不需要切换内存地址空间,所有线程共享同一进程的内存空间 |
开销 | 较大,涉及内存、页表切换等 | 较小,主要涉及寄存器和程序计数器的保存和恢复 |
速度 | 较慢 | 较快 |
并发性 | 进程间完全独立 | 线程间共享内存,通信与数据共享更高效 |
安全性 | 高,每个进程的内存空间是独立的,互不影响 | 低,线程间共享内存,容易发生数据竞争 |
线程的缺点
- 并发问题:如竞态条件和死锁,可能导致程序出错。、
- 调试困难:多线程的错误难以重现和调试。
- 同步复杂:需要使用锁机制,可能导致性能瓶颈。
- 共享内存问题:多线程共享内存,容易出现内存泄漏或竞争。
- 调度开销:线程过多时,系统调度开销增加,影响性能。
- 崩溃影响:一个线程崩溃可能导致整个进程崩溃。
cpp
#include<iostream>
#include<pthread.h>
using namespace std;
// 线程函数,线程执行时会调用这个函数
void* mythread(void* args)
{
cout <<"thread" << endl; // 输出"thread"到控制台,表示线程启动
int n = 0; // 定义一个整型变量n并初始化为0
int b = 10; // 定义一个整型变量b并初始化为10
int c = b / n; // 这里会导致除以零错误(n = 0),这是一个潜在的运行时错误
return nullptr; // 线程函数返回空指针,表示没有返回值
}
int main()
{
pthread_t tid; // 定义一个线程ID变量,用于标识线程
// 创建一个新线程,传递的参数分别为:线程ID、线程属性(nullptr表示默认属性)、线程执行的函数(mythread),以及传递给线程函数的参数(nullptr表示没有参数)
pthread_create(&tid, nullptr, mythread, nullptr);
// 等待线程执行完成(阻塞调用,直到tid对应的线程结束)
pthread_join(tid, nullptr);
return 0; // 程序正常结束
}
- 代码中的
int c = b / n;
这行会导致除以零 的运行时错误,因为n
被初始化为 0,这将引发程序崩溃(如果没有处理错误的话)。 - 在这里不仅仅是线程崩溃,进程也会随之崩溃。
、
线程的管理
- 同进程一样在OS中进程是通过
PCB
进行管理的,线程在OS系统中也有类似的i结构叫做TCB
.
TCB
TCB(Thread Control Block,线程控制块) 是操作系统用来管理线程的一个重要数据结构。每个线程在操作系统中都有一个唯一的 TCB,它保存了线程的状态信息和执行上下文。TCB 是操作系统在线程调度、切换和管理过程中使用的关键组件。
TCB的主要内容:
- 线程ID:唯一标识一个线程,操作系统通过线程ID来识别线程。
- 程序计数器(PC):指向线程当前正在执行的指令地址,确保线程从中断的地方继续执行。
- 寄存器状态:包括线程的寄存器值,确保在上下文切换时能恢复线程的执行状态。
- 线程状态:指示线程的当前状态,如就绪、运行、阻塞等。
- 堆栈指针:指向线程的栈,用于管理局部变量和函数调用。
- 优先级:线程的优先级,用于决定调度时的优先顺序。
TCB的作用:
- 调度:操作系统根据TCB中的信息来调度线程,决定哪些线程执行。
- 上下文切换:当切换线程时,操作系统保存当前线程的TCB并加载下一个线程的TCB,确保线程能继续执行。
- 管理线程生命周期:TCB帮助操作系统管理线程的创建、执行、阻塞和终止。
Linux中的TCB
在 Linux 操作系统 中,TCB(Thread Control Block,线程控制块) 是一个包含与线程相关的各种信息的数据结构。尽管 Linux 没有显式地使用 TCB
这个术语,但在 Linux 内核中,管理线程的结构体是 task_struct
,它类似于传统操作系统中的 TCB,用于存储线程的上下文信息和管理线程的执行。
task_struct
结构体
在 Linux 中,每个进程(包括线程)都由一个 task_struct
结构体来表示。这个结构体存储了与进程或线程相关的所有信息,它包含了线程调度、进程控制、内存管理、信号处理等多方面的信息。
task_struct
主要内容:
- 线程ID(PID/TID):每个线程有唯一的标识符,Linux 使用 PID(进程ID)和 TID(线程ID)来区分不同的进程和线程。
- 线程状态:记录线程的当前状态,如就绪、运行、阻塞等。
- 调度信息:包括调度策略、优先级、调度队列等信息,帮助操作系统决定线程的执行顺序。
- 程序计数器和寄存器:保存线程执行过程中使用的寄存器状态,确保上下文切换时线程能从正确位置恢复执行。
- 堆栈指针:指向线程的栈,存储局部变量和函数调用。
- 内存管理 :记录线程的虚拟内存、内存映射、文件描述符等资源信息。
调度信息*:包括调度策略、优先级、调度队列等信息,帮助操作系统决定线程的执行顺序。 - 程序计数器和寄存器:保存线程执行过程中使用的寄存器状态,确保上下文切换时线程能从正确位置恢复执行。
- 堆栈指针:指向线程的栈,存储局部变量和函数调用。
- 内存管理:记录线程的虚拟内存、内存映射、文件描述符等资源信息。
- 信号信息 :线程接收和响应信号(如
SIGTERM
等)的信息。