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

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

相关推荐
70asunflower11 分钟前
Ubuntu `tree` 命令完全指南:让目录结构一目了然
linux·数据库·ubuntu
老四啊laosi11 分钟前
【Linux系统】16. 进程程序替换
linux·exec·程序替换
ch3nyuyu35 分钟前
IO缓冲区
linux·服务器
wheeldown1 小时前
2026年4月横评三款主流远控软件实况实测:UU远程,Todesk,向日葵,综合性能 UU 远程表现最佳
linux·运维·服务器
诗句藏于尽头1 小时前
CentOS 7 源码编译安装 Python 3.11 完整教程
linux·centos·python3.11
bksczm1 小时前
Linux之基础开发工具(Ubuntu)之apt 、vim
linux·ubuntu·php
java_logo1 小时前
Docker 部署 Open WebUI + Ollama 完整教程(Windows / Linux 通用)—— 打造自己的本地OpenAI
linux·docker·容器·ollama·open-webui·open-webui部署·open-webui教程
小夏子_riotous1 小时前
Docker学习路径——8、Dockerfile
linux·运维·docker·容器·系统架构·centos·运维开发
叶子上的考拉1 小时前
解决远程连接服务器反应较慢问题
linux·运维·服务器
JackSparrow4141 小时前
彻底理解Java NIO(一)C语言实现 单进程+多进程+多线程 阻塞式I/O 服务器详解
java·linux·c语言·网络·后端·tcp/ip·nio