0

0

【Linux】从零开始认识多线程 --- 线程ID

雪夜

雪夜

发布时间:2025-07-21 12:26:36

|

832人浏览过

|

来源于php中文网

原创

在这个浮躁的时代

只有自律的人才能脱颖而出

-- 《觉醒年代》

1 前言

上一篇文章中讲解了线程控制的基本接口:

线程创建pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);: pthread_t *thread :输出型参数,线程ID。const pthread_attr_t *attr :线程属性(优先级,上下文…),默认传入nullptrvoid *(*start_routine) (void *) : 函数指针,线程需要执行的函数地址。void arg:想要传入到线程的信息,可以传入int,string地址或者传入一个类对象的地址。 线程等待pthread_join(pthread_t thread, void **retval); pthread_t thread:需要进行等待的线程IDvoid **retval: 获取的返回信息 线程终止pthread_cancel(pthread_t thread) pthread_t thread:需要进行终止的线程ID

需要深入理解的是线程传参!可以传递任何类型!注意传递堆空间的地址,保持线程独立性!

通过创建的线程我们看到了线程的tid,它和LWP不一样,是类似一个地址的存在,今天我们来详细分析一下线程ID。而且线程是有独立的栈空间的,这个独立栈空间是在哪里的?与线程ID有没有关系?

2 理解线程库与线程ID

我们先来写一个基础的创建线程的程序:

代码语言:javascript代码运行次数:0运行复制
<code class="javascript">#include <iostream>#include <pthread.h>#include <string>#include<unistd.h>std::string ToHex(int x){    char buffer[128];    snprintf(buffer , 128 , "0x%x" , x);    return buffer;}void *threadrun(void *args){    std::string name = static_cast<const char *>(args);    while (true)    {        std::cout << "name: " << name << "is running... ,tid: " << ToHex(pthread_self()) << std::endl;        sleep(1);    }}int main(){    pthread_t tid;    pthread_create(&tid, nullptr, threadrun, (void *)"thread-1");    std::cout << "new thread is running ,tid: " << tid << std::endl;    pthread_join(tid, nullptr);    return 0;}</code>

我们运行可以看到tid

【Linux】从零开始认识多线程 --- 线程ID

也可以通过ps -aL来查看查看运行线程的信息:

【Linux】从零开始认识多线程 --- 线程ID

显然tidLWP是不一样的,用户能获取的线程ID不是内核中的LWP,而内核中的LWP其实也不需要给用户呈现,tid是一个库内部自己维护的唯一值,因为库内部需要承担对线程的管理维护。

我们来深入理解库。 首先,库没被加载的时候是在磁盘中的,而线程库是一个动态库,本质上是一个文件。可执行程序也是在磁盘中。刚开始运行的时候,可执行程序会先变成一个进程,加载代码和数据到内存中,并同步创建PCB,页表,地址空间…当CPU调度到这个进程,会运行代码,进而动态创建多线程!

接下来,运行到创建线程的代码的前提是把库加载到进程的地址空间中!动态库也要加载到内存中。进程要使用动态库需要将动态库映射到进程地址空间的共享区中!代码运行到动态库中的代码时会跳转到共享区对应函数,在通过其偏移量映射到内存中库函数实现部分,完成动态库函数的调用!

【Linux】从零开始认识多线程 --- 线程ID

LInux内核只会维护轻量级进程,通过LWP(轻量级进程ID)维护,而用户层看到的是线程,需要的是线程的ID,线程的相关属性。上面我们提过线程是线程库维护的!接下来我们来看看线程库内部是如何维护管理的?如果库要管理线程和内核管理进程类似!同样遵循先描述,再组织

天工大模型
天工大模型

中国首个对标ChatGPT的双千亿级大语言模型

下载
动态库内部会有一个描述线程属性的内存块,每一个线程都会创建这样一个内存块结构,用来描述属性。这个内存块内部有线程在用户层面的基本属性,线程的独立栈结构
【Linux】从零开始认识多线程 --- 线程ID

也就是在库中创建了描述线程的相关结构体字段属性,因为是连续开辟的,所以管理方法类似数组。未来我们只要找到线程控制的地址即可!pthread_t id就是一个地址!通过这个地址我们就可以访问这个内存块的所有属性! 我们对比一下FILE* fopen()这个接口会返回一个文件指针(而不是一个文件对象),那么这个指针指向的文件是在哪里呢?在C标准库中!返回的也是一个地址(指针)。这和创建线程是一致的!@ 注意一点:在库里维护不一定要在库里开辟空间,都可以进行malloc的!

再来看pthread_join,如何理解?因为在库内部中线程结束时会直接return,并没有进行资源的释放,所以如果不进行join就会产生内存泄漏!join就是通过tid来找到对应位置来释放资源!

一个线程内部就可以有一个数组来维护一个栈结构!线程就独立的拥有自己的栈结构了!栈空间本质是地址空间的一部分区域!主线程使用自己的栈,新线程使用自己开劈的栈!

在用户层面是线程,内核层是轻量级进程,他们是1 :1的。

lwp是用来调度的单位:具有自己的系统调用,pthread库就是对这些系统调用的封装!线程概念的表现是在用户层的!
【Linux】从零开始认识多线程 --- 线程ID

Linux的线程 = pthread库中线程的属性集 + LWP

总的来说,pthread_t tid就是线程属性集合的起始虚拟地址 — 在pthread中进行维护。

3 线程局部存储

接下来我们,谈一下线程的局部存储。 我们设置一个全局变量gval,让新线程和主线程都不断打印,但是只有新线程进行++工作:

【Linux】从零开始认识多线程 --- 线程ID

可以看到他们的地址是一致的,因为他们共享地址空间,会访问到同一个gval!

今天如果我们不想让他们看到同一个gval呢?让他们各自拥有一份,我们可以使用编译选项__thread(只在linux有效,只能修饰内置类型)

代码语言:javascript代码运行次数:0运行复制
<code class="javascript">__thread int gval = 100;</code>
【Linux】从零开始认识多线程 --- 线程ID

可以看到此时主线程和新线程就是不一样的gval了!地址也不一样,说明新线程和主线程是各自拥有一份gval

这个全局变量,在加上__thread后就会在线程局部存储中各自储存一份,互不干扰!

Thanks♪(・ω・)ノ谢谢阅读!!!下一篇文章见!!!

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1030

2023.08.02

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

562

2023.09.20

全局变量怎么定义
全局变量怎么定义

本专题整合了全局变量相关内容,阅读专题下面的文章了解更多详细内容。

95

2025.09.18

python 全局变量
python 全局变量

本专题整合了python中全局变量定义相关教程,阅读专题下面的文章了解更多详细内容。

106

2025.09.18

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

490

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

202

2025.07.04

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1030

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

612

2024.08.29

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

76

2026.03.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
进程与SOCKET
进程与SOCKET

共6课时 | 0.4万人学习

swoole进程树解析
swoole进程树解析

共4课时 | 0.2万人学习

nginx浅谈
nginx浅谈

共15课时 | 0.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号