【Linux】线程概念与控制(3)_地址空间布局

hello~ 很高兴见到大家! 这次带来的是Linux系统中关于线程这部分的一些知识点,如果对你有所帮助的话,可否留下你宝贵的三连呢?
个 人 主 页 : 默|笙


文章目录


一、线程ID及进程地址空间布局

  1. 函数 pthread_create 调用之后会返回一个POSIX 线程 ID(pthread_t),这个线程 ID 跟 LWP(轻量级进程)不是同一个东西。LWP 是 Linux 内核底层用于唯一标识轻量级线程的内核线程 ID(TID),而 pthread_create 返回的线程 ID 本质上是一个用户态虚拟地址,它指向一个 glibc 库内部的 struct pthread 线程结构体,这个结构体内部封装了LWP、线程属性、栈信息、分离 / 可连接状态、返回值、同步变量等线程运行所需的全部上下文信息。
  2. 图中 struct pthread 线程结构体,是由 glibc 在 pthread_create 内部通过 mmap 系统调用分配的匿名私有内存块,位于进程地址空间的mmap 区域(mmap区域和共享区挨在一起,一个私有,一个共享)。这块内存会一次性分配,包含 struct pthread、线程局部存储、线程栈等完整线程资源,仅属于当前进程的当前线程,不与其他进程共享
  3. 函数 pthread_create 内部会调用 clone 系统调用来完成线程的创建,因此 pthread 系列函数本质上就是对 Linux 轻量级进程相关系统调用的封装。
  4. 我们用 pthread_create 函数传递参数给线程要执行的函数时,参数是怎么传入的呢?系统会把参数保存到该线程对应的 pthread 结构体内部,线程执行时再从中取出使用。我们能够通过 pthread_join 获取到线程的返回值,也正是依靠 pthread 结构体来存储返回值
  5. 主线程拥有自己独立的栈区,这个栈区仅供主线程使用,并不在 mmap 区域。而通过 pthread_create 创建的子线程,每个都有自己专属的线程栈,这些线程栈统一位于 mmap 匿名区域中。
  1. 我们也可以梳理一下为什么线程需要被等待:线程结束后,LWP 就消亡了,而pthread 结构体与内核管理轻量级进程的 task_struct 是 1:1 的关系,线程函数的返回值会由 glibc 保存到 pthread 结构体中,而我们要获取这些信息,就必须通过 pthread_join 从结构体里读取,并由库函数释放这块通过 mmap 申请的内存空间。因此,如果不等待、不回收线程,就会造成内存泄漏。
  2. 再来讲一下 pthread_create 函数的第二个参数 ------ 线程属性,线程的各类属性被封装在 pthread_attr_t 结构体中。pthread_attr_t 线程属性结构体是 struct pthread 的内部成员,它会随线程结构体一同创建、一同存储在 mmap 匿名区、一同被释放。日常编程中一般不需要自定义属性,给第二个参数传递 NULL 时,库函数会自动使用默认属性初始化线程结构体内部的属性成员。
cpp 复制代码
// 1. 线程属性结构体 (你问的 pthread_attr_t)
typedef struct {
    int detachstate;      // 分离状态:可结合 / 分离
    size_t stacksize;     // 线程栈大小
    void *stackaddr;      // 栈地址
    int sched_policy;     // 调度策略
} pthread_attr_t;

// 2. 核心线程结构体 struct pthread
struct pthread {
    // 内核LWP标识 (1:1对应task_struct)
    pid_t tid;            // LWP号,系统调用gettid获取
    pid_t pid;            // 所属进程PID

    // 线程属性结构体 直接嵌套在内部
    pthread_attr_t attr;  

    // 线程运行核心信息
    void *(*start_routine)(void *);  // 线程入口函数
    void *arg;                        // 线程参数
    void *retval;                     // 线程返回值(join获取)

    // 内存信息(mmap匿名区分配)
    void *stack_base;    // 线程栈基地址
    size_t stack_size;   // 线程栈总大小

    // 同步控制(用于pthread_join等待)
    pthread_mutex_t join_mutex;
    pthread_cond_t join_cond;
};

// pthread_t 本质是指向该结构体的指针
typedef struct pthread *pthread_t;
  1. C++11 及后续标准提供了官方的线程库,该库底层封装了不同操作系统的原生线程实现(Linux 下封装 pthread,Windows 下封装系统原生线程接口),对外暴露统一的跨平台接口,让一份线程代码可以在 Windows、Linux 等不同系统上直接运行,实现跨平台特性。

今天的分享就到此结束啦,如果对读者朋友们有所帮助的话,可否留下宝贵的三连呢~~
让我们共同努力, 一起走下去!

相关推荐
傲世仙尊24 分钟前
IO流起步-从fopen到文件描述符fd
linux
Rabitebla27 分钟前
【Linux系统编程】 指令(二):一条路径是怎么定位到文件的
linux·c++·笔记·学习·算法
人工智能培训33 分钟前
大语言模型:从语言理解到通用智能的跃迁
linux·服务器·前端·人工智能
顶点多余35 分钟前
9.20 知识点查漏补缺
linux·面试·职场和发展
阿明61 小时前
Linux进程【Linux】
linux·运维·服务器
Android系统攻城狮1 小时前
Linux Gstreamer深度解析之gst_audio_resampler_update调用流程与实战(三十)
linux·运维·服务器·gstreamer音视频·音视频进阶
qetfw1 小时前
Linux tcpdump 抓包实战:网卡、主机、端口过滤与 PCAP 分析
linux·tcpdump
pilifeng11 小时前
Ubuntu Linux 目录结构详解
linux·ubuntu
电棍2332 小时前
ubuntu网卡失效
linux
律宏阔2 小时前
VMware 能识别 USB 设备,但无法连接(灰色)
linux