一、线程 ID 深度解析用户级与内核级的双重身份提到线程 IDTID很多开发者会混淆两个完全不同的概念 —— 用户级线程 IDpthread_t和内核级线程 IDLWP。这两种 ID 的作用、实现方式和作用域截然不同是理解线程底层逻辑的第一个关键点。1.1 内核级线程 IDLWP内核视角的唯一标识在 Linux 内核中并不存在专门的 “线程结构体”线程本质是轻量级进程Light Weight ProcessLWP内核通过task_struct结构体统一管理进程和线程。内核为每个task_struct分配的全局唯一标识就是内核级线程 IDLWP。作用域系统全局唯一内核调度线程时就是以 LWP 作为识别依据。获取方式通过ps -aL命令查看输出结果中的LWP列即为内核级线程 ID。在代码中通过gettid()系统调用获取需包含sys/syscall.h头文件。特性主线程的 LWP 与进程 IDPID相同子线程的 LWP 是独立的全局唯一值。示例通过 ps 命令查看线程 LWP代码语言javascriptAI代码解释# 编译运行一个多线程程序后查看线程信息 ps -aL | grep 程序名输出结果代码语言javascriptAI代码解释12345 12345 pts/0 00:00:00 thread_demo # 主线程PID12345LWP12345 12345 12346 pts/0 00:00:00 thread_demo # 子线程1PID12345LWP12346 12345 12347 pts/0 00:00:00 thread_demo # 子线程2PID12345LWP12347代码示例获取内核级线程 IDLWP代码语言javascriptAI代码解释#include stdio.h #include sys/syscall.h #include unistd.h int main() { // gettid()是系统调用需通过syscall函数调用 pid_t lwp syscall(SYS_gettid); printf(内核级线程IDLWP%d\n, lwp); printf(进程IDPID%d\n, getpid()); return 0; }1.2 用户级线程 IDpthread_t线程库视角的进程内标识用户级线程 ID 是 POSIX 线程库pthread定义的标识类型为pthread_t用于在进程内唯一识别线程。作用域仅在当前进程内有效内核不识别pthread_t类型它是线程库自行维护的标识。获取方式通过pthread_create函数的第一个参数输出获取新创建线程的pthread_t。通过pthread_self()函数获取当前线程的pthread_t。本质在 Linux 的 NPTLNative POSIX Thread Library实现中pthread_t本质是进程地址空间中的一个虚拟地址指向线程的控制块TCBThread Control Block结构体。代码示例获取用户级线程 IDpthread_t代码语言javascriptAI代码解释#include stdio.h #include pthread.h #include unistd.h void *thread_func(void *arg) { // 获取当前线程的用户级ID pthread_t tid pthread_self(); printf(子线程用户级线程ID %lu本质是虚拟地址\n, (unsigned long)tid); return NULL; } int main() { pthread_t tid; pthread_create(tid, NULL, thread_func, NULL); printf(主线程子线程用户级ID %lu\n, (unsigned long)tid); pthread_join(tid, NULL); return 0; }编译运行代码语言javascriptAI代码解释gcc pthread_t_demo.c -o pthread_t_demo -lpthread ./pthread_t_demo输出结果代码语言javascriptAI代码解释主线程子线程用户级ID 140703347508992 子线程用户级线程ID 140703347508992本质是虚拟地址1.3 两种线程 ID 的核心区别特性内核级线程 IDLWP用户级线程 IDpthread_t定义者Linux 内核POSIX 线程库pthread作用域系统全局唯一进程内唯一本质整数pid_t 类型虚拟地址指向 TCB内核是否识别是调度的唯一标识否仅线程库使用获取方式syscall(SYS_gettid)、ps -aLpthread_create、pthread_self()理解这两种 ID 的区别能避免很多多线程开发中的坑。例如不能用pthread_t作为系统级标识传递给其他进程因为它在进程外没有意义而 LWP 是系统全局唯一的可以用于跨进程识别线程。二、进程地址空间布局线程在内存中的 “居住地”要理解线程的运行机制必须清楚线程在进程地址空间中的分布 —— 线程的栈、线程控制块TCB、线程局部存储TLS等都位于进程地址空间的特定区域。Linux 进程的虚拟地址空间从低地址到高地址分为以下区域代码段、已初始化数据段、未初始化数据段、堆区、共享区mmap 区域、栈区、内核空间。2.1 线程相关内存区域的分布2.1.1 主线程与子线程的栈分布主线程栈位于进程地址空间的栈区从高地址向低地址生长支持动态增长通过写时拷贝和内核分配实现栈大小默认通常为 8MB超出上限会触发栈溢出段错误。子线程栈位于进程地址空间的共享区mmap 区域通过mmap系统调用分配大小固定默认通常为 8MB不支持动态增长栈空间用尽会直接触发段错误。子线程栈位于共享区的原因pthread 库是动态链接库加载到进程的共享区子线程由 pthread 库创建其栈空间也分配在共享区方便线程库管理。2.1.2 线程控制块TCB的分布线程控制块TCB是 pthread 库维护的结构体在 glibc 源码中为struct pthread存储线程的所有状态信息线程 ID、栈地址、调度优先级、取消状态等。TCB 位于子线程栈的末端pthread_t就是该结构体的虚拟地址。2.1.3 线程局部存储TLS的分布线程局部存储Thread Local Storage是线程的私有数据区域用于存储线程独有的全局变量如__thread修饰的变量位于共享区每个线程有独立的 TLS 空间互不干扰。2.2 进程地址空间布局示意图2.3 代码验证子线程栈的位置通过代码打印主线程栈和子线程栈的地址验证它们的分布区域代码语言javascriptAI代码解释#include stdio.h #include pthread.h #include unistd.h // 主线程栈变量位于栈区 int main_stack_var; void *thread_func(void *arg) { // 子线程栈变量位于共享区 int thread_stack_var; printf(子线程栈变量地址 %p共享区\n, thread_stack_var); printf(子线程TCB地址pthread_t %p\n, (void*)pthread_self()); return NULL; } int main() { printf(主线程栈变量地址 %p栈区\n, main_stack_var); printf(主线程全局变量地址 %p数据段\n, main_stack_var); pthread_t tid; pthread_create(tid, NULL, thread_func, NULL); pthread_join(tid, NULL); return 0; }运行结果代码语言javascriptAI代码解释主线程栈变量地址 0x7ffeefbff5ac栈区高地址 主线程全局变量地址 0x55f8d7a7c010数据段低地址 子线程栈变量地址 0x7f6b3a7fc7ac共享区地址介于堆和栈之间 子线程TCB地址pthread_t 0x7f6b3a7fd700从结果可以看出主线程栈变量地址0x7ffe 开头高于子线程栈变量地址0x7f6b 开头验证了主线程栈位于栈区更高地址子线程栈位于共享区。三、线程栈深度解析特性、实现与注意事项线程栈是线程的私有数据区域用于存储局部变量、函数调用参数和返回值其实现细节直接影响线程的稳定性和安全性。3.1 线程栈的核心特性3.1.1 主线程栈 vs 子线程栈特性主线程栈子线程栈分配方式进程创建时内核自动分配pthread 库通过mmap系统调用分配存储区域栈区共享区mmap 区域增长方向从高地址向低地址从高地址向低地址是否支持动态增长是默认 8MB可通过ulimit调整否大小固定默认 8MB栈溢出表现超出上限触发段错误SIGSEGV栈空间用尽触发段错误SIGSEGV3.1.2 子线程栈的分配源码分析子线程栈的分配逻辑位于 glibc 的nptl/allocatestack.c文件的allocate_stack函数中核心步骤如下获取线程栈大小用户通过pthread_attr_setstacksize设置未设置则使用默认值 8MB。尝试从pthread库的栈缓存中分配栈空间缓存命中则直接使用。缓存未命中则调用mmap系统调用分配匿名内存私有、匿名、栈类型代码语言javascriptAI代码解释mem mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);在分配的栈空间末端设置线程控制块TCB。设置栈保护区域Guard Page通过mprotect设置为PROT_NONE防止栈溢出访问到其他内存区域。关键源码片段glibc-2.4代码语言javascriptAI代码解释// 分配栈空间allocatestack.c mem mmap(NULL, size, prot, MAP_PRIVATE | MAP_ANONYMOUS | ARCH_MAP_FLAGS, -1, 0); if (mem MAP_FAILED) { // 分配失败处理 return errno; } // 在栈末端放置TCBTLS_TCB_AT_TP模式 pd (struct pthread *)((char *)mem size - coloring) - 1; // 设置栈保护区域Guard Page char *guard mem; if (mprotect(guard, guardsize, PROT_NONE) ! 0) { // 保护区域设置失败处理 munmap(mem, size); return errno; }3.2 线程栈的常见问题与注意事项3.2.1 栈溢出问题子线程栈大小固定若局部变量过大如大型数组或递归调用过深会导致栈溢出触发段错误。错误示例子线程栈溢出代码语言javascriptAI代码解释#include stdio.h #include pthread.h void *thread_overflow(void *arg) { // 定义10MB的局部数组超出默认8MB栈大小触发栈溢出 char big_array[1024 * 1024 * 10]; printf(子线程尝试使用10MB局部数组栈溢出\n); return NULL; } int main() { pthread_t tid; pthread_create(tid, NULL, thread_overflow, NULL); pthread_join(tid, NULL); return 0; }运行结果代码语言javascriptAI代码解释Segmentation fault (core dumped) # 栈溢出触发段错误解决方案避免在子线程中使用大型局部变量改用动态内存分配malloc/new。通过pthread_attr_setstacksize设置更大的栈大小。正确示例设置子线程栈大小代码语言javascriptAI代码解释#include stdio.h #include pthread.h #include unistd.h void *thread_large_stack(void *arg) { // 定义10MB局部数组栈大小已设置为16MB char big_array[1024 * 1024 * 10]; printf(子线程成功使用10MB局部数组\n); return NULL; } int main() { pthread_t tid; pthread_attr_t attr; pthread_attr_init(attr); // 设置栈大小为16MB16*1024*1024字节 size_t stack_size 16 * 1024 * 1024; pthread_attr_setstacksize(attr, stack_size); pthread_create(tid, attr, thread_large_stack, NULL); pthread_join(tid, NULL); pthread_attr_destroy(attr); return 0; }3.2.2 线程栈的访问权限子线程栈是线程私有区域但同一进程的其他线程可以通过指针访问到该栈因为共享进程地址空间可能导致数据竞争或非法访问。示例线程间访问栈数据不推荐代码语言javascriptAI代码解释#include stdio.h #include pthread.h #include unistd.h int *g_thread_stack_ptr; // 全局指针指向子线程栈变量 void *thread_func(void *arg) { int thread_var 100; g_thread_stack_ptr thread_var; // 将子线程栈变量地址赋值给全局指针 sleep(2); // 等待主线程访问 return NULL; } int main() { pthread_t tid; pthread_create(tid, NULL, thread_func, NULL); sleep(1); // 等待子线程初始化变量 // 主线程通过全局指针访问子线程栈变量存在风险 printf(主线程访问子线程栈变量 %d\n, *g_thread_stack_ptr); pthread_join(tid, NULL); return 0; }注意这种做法存在严重风险若子线程退出后主线程再访问该指针会导致野指针访问子线程栈已被释放。线程间数据传递应使用全局变量、堆内存或线程安全的队列避免直接访问对方栈空间。四、页表与内存管理线程共享地址空间的底层支撑线程共享进程的虚拟地址空间本质是共享进程的页表Page Table。页表是虚拟地址到物理地址的映射表由 MMU内存管理单元硬件解析是线程共享内存资源的底层支撑。4.1 页表的核心概念与结构4.1.1 页表的作用将进程的虚拟地址映射到物理内存的页框Page Frame。实现虚拟地址空间的连续性和物理内存的离散分配解决内存碎片问题。提供内存访问权限控制读、写、执行。4.1.2 页表的层级结构Linux 采用多级页表32 位系统为二级页表64 位系统为四级页表避免单级页表占用过多连续物理内存。以 32 位系统为例虚拟地址分为三部分页目录号10 位、页表号10 位、页内偏移12 位。页目录表PGD存储 1024 个页目录项每个项指向一个页表。页表PTE每个页表存储 1024 个页表项每个项指向一个物理页框。CR3 寄存器存储当前进程的页目录表物理地址是地址转换的起点。4.1.3 页表项PTE的结构页表项pte_t是页表中的基本单元存储虚拟页到物理页框的映射关系和访问权限定义在include/linux/mm_types.h中代码语言javascriptAI代码解释typedef struct { unsigned long pte; } pte_t; // 页表项 typedef struct { unsigned long pgd; } pgd_t; // 页目录项页表项的关键标志位定义在include/linux/pgtable.hL_PTE_PRESENT10页面是否在物理内存中。L_PTE_WRITE15页面是否可写。L_PTE_EXEC16页面是否可执行。L_PTE_DIRTY17页面是否被修改脏页。L_PTE_USER14用户态是否可访问。4.2 线程共享页表的底层逻辑同一进程的所有线程共享同一个页目录表PGD和页表PTE因此线程访问的虚拟地址通过相同的页表映射到物理内存实现内存资源共享。线程切换时无需切换页表CR3 寄存器值不变仅需切换线程的私有上下文寄存器、栈指针等切换开销远小于进程。若一个线程修改了共享内存如全局变量其他线程通过相同的页表访问到的是同一个物理页框能立即看到修改后的数据。4.3 页表与线程安全的关联页表本身是线程共享的但 MMU 在访问页表时是原子操作不会出现数据竞争。但线程访问共享内存中的数据时可能出现数据竞争需要通过互斥锁等同步机制保护这与页表本身无关而是线程调度的随机性导致的。示例线程共享全局变量依赖页表共享代码语言javascriptAI代码解释#include stdio.h #include pthread.h #include unistd.h int g_shared_var 0; // 全局变量位于数据段线程共享 pthread_mutex_t mutex; // 互斥锁保护共享变量 void *thread_incr(void *arg) { for (int i 0; i 10000; i) { pthread_mutex_lock(mutex); g_shared_var; // 线程共享全局变量通过页表映射到同一物理页 pthread_mutex_unlock(mutex); } return NULL; } int main() { pthread_mutex_init(mutex, NULL); pthread_t tid1, tid2; pthread_create(tid1, NULL, thread_incr, NULL); pthread_create(tid2, NULL, thread_incr, NULL); pthread_join(tid1, NULL); pthread_join(tid2, NULL); printf(共享变量最终值%d预期20000\n, g_shared_var); pthread_mutex_destroy(mutex); return 0; }编译运行代码语言javascriptAI代码解释gcc shared_var_demo.c -o shared_var_demo -lpthread ./shared_var_demo输出结果代码语言javascriptAI代码解释共享变量最终值20000预期20000该示例中两个线程通过共享页表访问同一全局变量的物理内存互斥锁保证了访问的原子性避免数据竞争。五、线程封装实战从原生 API 到优雅的 C 封装类理解了线程的底层逻辑后我们可以基于 pthread 库封装一个通用的 C 线程类屏蔽原生 API 的繁琐细节支持线程创建、启动、等待、分离、设置名称等功能同时保证线程安全。5.1 线程封装的设计目标简化线程创建流程支持传递任意参数的线程函数。支持线程的 joinable/detached 状态切换。支持设置线程名称方便调试。支持线程的异常安全避免资源泄漏。提供简洁的接口Start、Join、Detach、Stop。5.2 线程封装类实现C11 及以上代码语言javascriptAI代码解释#pragma once #include iostream #include string #include functional #include pthread.h #include unistd.h #include cstring #include atomic namespace ThreadModule { // 线程状态枚举 enum class ThreadStatus { NEW, // 未启动 RUNNING, // 运行中 STOPPED // 已停止 }; // 线程封装类 class Thread { public: // 线程函数类型支持任意参数通过std::function封装 using ThreadFunc std::functionvoid(); // 构造函数传入线程函数和线程名称可选 explicit Thread(ThreadFunc func, const std::string name ) : func_(std::move(func)), name_(name), tid_(0), status_(ThreadStatus::NEW), is_joinable_(true) { // 自动生成线程名称若未指定 if (name_.empty()) { static std::atomicuint32_t thread_cnt(0); name_ Thread- std::to_string(thread_cnt); } } // 析构函数确保线程资源释放 ~Thread() { // 若线程是joinable状态且未停止分离线程避免资源泄漏 if (status_ ThreadStatus::RUNNING is_joinable_) { pthread_detach(tid_); std::cout 线程[ name_ ]自动分离避免资源泄漏 std::endl; } } // 禁用拷贝构造和赋值运算符线程ID不可拷贝 Thread(const Thread) delete; Thread operator(const Thread) delete; // 移动构造和移动赋值支持线程对象转移 Thread(Thread other) noexcept : func_(std::move(other.func_)), name_(std::move(other.name_)), tid_(other.tid_), status_(other.status_), is_joinable_(other.is_joinable_) { other.tid_ 0; other.status_ ThreadStatus::NEW; } Thread operator(Thread other) noexcept { if (this ! other) { // 释放当前线程资源 if (status_ ThreadStatus::RUNNING is_joinable_) { pthread_detach(tid_); } // 转移资源 func_ std::move(other.func_); name_ std::move(other.name_); tid_ other.tid_; status_ other.status_; is_joinable_ other.is_joinable_; // 重置源对象 other.tid_ 0; other.status_ ThreadStatus::NEW; } return *this; } // 启动线程 bool Start() { if (status_ ! ThreadStatus::NEW) { std::cerr 线程[ name_ ]已启动无法重复启动 std::endl; return false; } // 创建线程传入线程函数和当前对象指针 int ret pthread_create(tid_, nullptr, ThreadRoutine, this); if (ret ! 0) { std::cerr 线程[ name_ ]创建失败错误信息 strerror(ret) std::endl; return false; } status_ ThreadStatus::RUNNING; std::cout 线程[ name_ ]启动成功用户级ID (unsigned long)tid_ std::endl; return true; } // 等待线程结束joinable状态下 bool Join() { if (!is_joinable_) { std::cerr 线程[ name_ ]分离状态无法等待 std::endl; return false; } if (status_ ! ThreadStatus::RUNNING) { std::cerr 线程[ name_ ]未运行或已停止无需等待 std::endl; return false; } // 等待线程结束 int ret pthread_join(tid_, nullptr); if (ret ! 0) { std::cerr 线程[ name_ ]等待失败错误信息 strerror(ret) std::endl; return false; } status_ ThreadStatus::STOPPED; std::cout 线程[ name_ ]已停止等待完成 std::endl; return true; } // 分离线程设置为detached状态 bool Detach() { if (!is_joinable_) { std::cerr 线程[ name_ ]已分离无需重复分离 std::endl; return false; } if (status_ ! ThreadStatus::RUNNING) { std::cerr 线程[ name_ ]未运行无法分离 std::endl; return false; } int ret pthread_detach(tid_); if (ret ! 0) { std::cerr 线程[ name_ ]分离失败错误信息 strerror(ret) std::endl; return false; } is_joinable_ false; std::cout 线程[ name_ ]分离成功 std::endl; return true; } // 强制终止线程谨慎使用 bool Stop() { if (status_ ! ThreadStatus::RUNNING) { std::cerr 线程[ name_ ]未运行无需终止 std::endl; return false; } int ret pthread_cancel(tid_); if (ret ! 0) { std::cerr 线程[ name_ ]终止失败错误信息 strerror(ret) std::endl; return false; } // 等待线程终止并回收资源 if (is_joinable_) { pthread_join(tid_, nullptr); } status_ ThreadStatus::STOPPED; std::cout 线程[ name_ ]已强制终止 std::endl; return true; } // 获取线程名称 std::string GetName() const { return name_; } // 获取用户级线程ID pthread_t GetTid() const { return tid_; } // 获取线程状态 ThreadStatus GetStatus() const { return status_; } // 判断线程是否为joinable状态 bool IsJoinable() const { return is_joinable_; } private: // 线程入口函数必须是静态函数无this指针 static void* ThreadRoutine(void* arg) { Thread* thread static_castThread*(arg); if (thread nullptr) { std::cerr 线程入口参数为空 std::endl; return nullptr; } // 设置线程名称Linux非标准函数用于调试 pthread_setname_np(pthread_self(), thread-name_.c_str()); try { // 执行线程函数 if (thread-func_) { thread-func_(); } } catch (const std::exception e) { std::cerr 线程[ thread-name_ ]执行异常 e.what() std::endl; } catch (...) { std::cerr 线程[ thread-name_ ]未知异常 std::endl; } // 线程执行完毕更新状态 thread-status_ ThreadStatus::STOPPED; std::cout 线程[ thread-name_ ]执行完毕 std::endl; return nullptr; } private: ThreadFunc func_; // 线程要执行的函数 std::string name_; // 线程名称 pthread_t tid_; // 用户级线程ID ThreadStatus status_; // 线程状态 bool is_joinable_; // 是否为joinable状态默认是 }; }5.3 线程封装类的核心特性解析5.3.1 支持任意参数的线程函数通过std::functionvoid()封装线程函数结合std::bind或lambda 表达式可以传递任意参数的函数代码语言javascriptAI代码解释#include iostream #include functional #include Thread.hpp // 无参数函数 void FuncWithoutArgs() { std::cout 无参数线程函数运行中 std::endl; sleep(1); } // 单参数函数 void FuncWithOneArg(int num) { std::cout 单参数线程函数num num std::endl; sleep(1); } // 多参数函数 void FuncWithMultiArgs(const std::string str, double val) { std::cout 多参数线程函数str str , val val std::endl; sleep(1); } int main() { using namespace ThreadModule; // 1. 无参数线程 Thread t1(FuncWithoutArgs, NoArgThread); t1.Start(); // 2. 单参数线程使用std::bind Thread t2(std::bind(FuncWithOneArg, 100), OneArgThread); t2.Start(); // 3. 多参数线程使用lambda表达式 Thread t3([]() { FuncWithMultiArgs(Hello, 3.14); }, MultiArgThread); t3.Start(); // 4. 带捕获的lambda线程 int x 200; Thread t4([x]() { std::cout Lambda线程捕获x x std::endl; sleep(1); }, LambdaThread); t4.Start(); // 等待所有线程结束 t1.Join(); t2.Join(); t3.Join(); t4.Join(); return 0; }5.3.2 线程名称设置与调试通过pthread_setname_np函数设置线程名称方便通过ps -aL或调试工具如 GDB识别线程代码语言javascriptAI代码解释# 查看线程名称 ps -aL | grep 程序名输出结果代码语言javascriptAI代码解释12345 12345 pts/0 00:00:00 thread_demo # 主线程 12345 12346 pts/0 00:00:00 NoArgThread # 线程1NoArgThread 12345 12347 pts/0 00:00:00 OneArgThread # 线程2OneArgThread 12345 12348 pts/0 00:00:00 MultiArgThread # 线程3MultiArgThread 12345 12349 pts/0 00:00:00 LambdaThread # 线程4LambdaThread5.3.3 异常安全与资源管理析构函数自动处理线程资源若线程是joinable状态且未停止自动分离线程pthread_detach避免资源泄漏。禁用拷贝构造和赋值运算符防止线程 ID 重复或资源竞争。支持移动构造和移动赋值允许线程对象在不同作用域间转移。5.3.4 线程状态管理通过ThreadStatus枚举跟踪线程状态NEW/RUNNING/STOPPED避免重复启动、重复等待等错误操作。5.4 线程封装类的使用示例综合案例代码语言javascriptAI代码解释#include iostream #include vector #include chrono #include Thread.hpp using namespace ThreadModule; using namespace std::chrono; // 计算任务计算start到end的累加和 void CalcSum(int start, int end, long long result, pthread_mutex_t mutex) { long long sum 0; for (int i start; i end; i) { sum i; } // 加锁保护共享结果 pthread_mutex_lock(mutex); result sum; pthread_mutex_unlock(mutex); std::cout 线程[ Thread::GetCurrentThreadName() ]计算范围[ start , end ]局部和 sum std::endl; } int main() { // 初始化互斥锁 pthread_mutex_t mutex; pthread_mutex_init(mutex, nullptr); // 共享结果 long long total_sum 0; // 任务拆分4个线程计算1~100000000的累加和 const int total 100000000; const int thread_num 4; const int step total / thread_num; std::vectorThread threads; auto start_time high_resolution_clock::now(); // 创建4个线程 for (int i 0; i thread_num; i) { int start i * step 1; int end (i thread_num - 1) ? total : (i 1) * step; // 绑定任务函数和参数 threads.emplace_back( [start, end, total_sum, mutex]() { CalcSum(start, end, total_sum, mutex); }, CalcThread- std::to_string(i) ); // 启动线程 threads.back().Start(); } // 等待所有线程结束 for (auto thread : threads) { thread.Join(); } auto end_time high_resolution_clock::now(); auto duration duration_castmilliseconds(end_time - start_time).count(); // 输出结果 std::cout std::endl; std::cout 总计算范围1~ total std::endl; std::cout 累加和结果 total_sum std::endl; std::cout 总耗时 duration ms std::endl; std::cout std::endl; // 销毁互斥锁 pthread_mutex_destroy(mutex); return 0; }编译运行代码语言javascriptAI代码解释g thread_demo.cpp -o thread_demo -lpthread -stdc11 ./thread_demo输出结果代码语言javascriptAI代码解释线程[CalcThread-0]启动成功用户级ID 140703347508992 线程[CalcThread-1]启动成功用户级ID 140703339116288 线程[CalcThread-2]启动成功用户级ID 140703330723584 线程[CalcThread-3]启动成功用户级ID 140703322330880 线程[CalcThread-0]计算范围[1,25000000]局部和 312500012500000 线程[CalcThread-1]计算范围[25000001,50000000]局部和 937500025000000 线程[CalcThread-2]计算范围[50000001,75000000]局部和 1562500037500000 线程[CalcThread-3]计算范围[75000001,100000000]局部和 2187500050000000 线程[CalcThread-0]执行完毕 线程[CalcThread-1]执行完毕 线程[CalcThread-2]执行完毕 线程[CalcThread-3]执行完毕 线程[CalcThread-0]已停止等待完成 线程[CalcThread-1]已停止等待完成 线程[CalcThread-2]已停止等待完成 线程[CalcThread-3]已停止等待完成 总计算范围1~100000000 累加和结果5000000050000000 总耗时32ms六、pthread 库源码深度解析线程创建的底层流程要真正理解线程封装的本质必须深入pthread库的源码看看pthread_create函数是如何创建线程的。以下基于 glibc-2.4 的nptl/pthread_create.c源码解析线程创建的核心流程。