【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 等不同系统上直接运行,实现跨平台特性。

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

相关推荐
sulikey3 小时前
Linux ext2文件系统结构
linux·操作系统·文件系统·linux文件系统·ext2·ext2文件系统
白菜欣4 小时前
Linux — 进程控制
android·linux·运维
皮卡狮5 小时前
Linux开发专属工具
linux
weixin_421725265 小时前
Linux 编程语言全解析:C、C++、Python、Go、Rust 谁更强?
linux·python·go·c·编程语言
Tolalal5 小时前
Vmware Ubuntu虚拟机扩容
linux·运维·ubuntu
我星期八休息6 小时前
Linux系统编程—基础IO
linux·运维·服务器·c语言·c++·人工智能·算法
Shingmc36 小时前
【Linux】数据链路层
linux·服务器·网络
bksczm6 小时前
文件描述符
linux
Goldbioinformatics6 小时前
Windows版Claude Cowork启动Linux问题
linux·运维·windows