Linux 多线程,线程分离
1.多线程1.创建多线程示例代码使用for循环去创建一个一个的线程让它们去循环的打印出自己的pid和线程tid创建完线程之后不要忘记去释放掉线程资源避免内存泄漏。#include iostream #include pthread.h #include unistd.h #include vector using namespace std; #define NUM 8 struct ThreadData { string threadname; }; string Tohex(pthread_t tid) { char buffer[128]; snprintf(buffer,sizeof(buffer),0x%lx,tid); return buffer; } void InitThreadname(ThreadData*td,int i) { td-threadnamethreadto_string(i); } void*threadRoutine(void*args) { ThreadData*tdstatic_castThreadData*(args); int i0; while(i10) { coutpid: getpid(), tid : Tohex(pthread_self()), threadname: td-threadnameendl; sleep(1); i; } delete td; return nullptr; } int main() { vectorpthread_t tids; for(int i0;iNUM;i) { pthread_t tid; //这样子写是不可以的理论上面这个是在主线程创建的所以还是创建是在主线程的栈上面for循环结束了也就销毁了 //ThreadData td; ThreadData*tdnew ThreadData;//创建在堆上面每次创建都访问的是不同的堆空间这样子每一个线程都原来属于自己的堆空间 InitThreadname(td,i); pthread_create(tid,nullptr,threadRoutine,td); tids.push_back(tid); } for(int i0;itids.size();i) { pthread_join(tids[i],nullptr); } }使用ps-aL来查看监控中的轻量化进程查看创建情况。while :; do ps -aL|head -1ps -aL|grep my|grep -v grep;sleep 1;done运行结果从左侧代码的运行结果可以看出来这些线程的pid都是一样的说明都是一个进程创建出来的右侧可以看出来pid一样但是LWP不一样说明确实瞬间创建出来了多个线程。ps这里也应该明白虽然线程好像是创建在不同的堆上面好像看样子是每一个线程都拥有了自己的空间互相不打扰但是线程之间是没有秘密的一个线程想要知道其他线程的数据是很简单的之前找到了tid是动态库存储线程数据的起始地址只要线程获取到了这个tid也就可以获取到数据了。2.线程中的变量和全局变量2.1 线程中创建的变量在单个线程中每个线程都是有自己的独立线程栈的所以在线程执行函数里面定义了一个变量这个变量会在每一个线程中存在一份。示例代码在线程执行函数里面定义一个变量查看线程中变量的地址和在对test_i加加两次后test_i的值。#include iostream #include pthread.h #include unistd.h #include vector using namespace std; #define NUM 8 struct ThreadData { string threadname; }; string Tohex(pthread_t tid) { char buffer[128]; snprintf(buffer,sizeof(buffer),0x%lx,tid); return buffer; } void InitThreadname(ThreadData*td,int i) { td-threadnamethreadto_string(i); } void*threadRoutine(void*args) { ThreadData*tdstatic_castThreadData*(args); int i0; int test_i0; while(i2) { coutpid: getpid(), tid : Tohex(pthread_self()), threadname: td-threadname test_i: test_iendl; sleep(1); i; test_i; } delete td; return nullptr; } int main() { vectorpthread_t tids; for(int i0;iNUM;i) { pthread_t tid; //这样子写是不可以的理论上面这个是在主线程创建的所以还是创建是在主线程的栈上面for循环结束了也就销毁了 //ThreadData td; ThreadData*tdnew ThreadData;//创建在堆上面每次创建都访问的是不同的堆空间这样子每一个线程都原来属于自己的堆空间 InitThreadname(td,i); pthread_create(tid,nullptr,threadRoutine,td); tids.push_back(tid); } for(int i0;itids.size();i) { pthread_join(tids[i],nullptr); } }运行结果可以看到有10个test_i的地址说明每一个线程中都存在这一个变量并且对自己的变量进行操作没有影响其他的线程。2.2 全局变量如果这个变量是全局变量的话那情况就不一样了因为全局变量只有一份线程肯定是看得到这个全局变量的所以在多线程中对这个变量进行操作就都是对这个全局变量进行操作了代码示例#include iostream #include pthread.h #include unistd.h #include vector using namespace std; #define NUM 8 int test_i0; struct ThreadData { string threadname; }; string Tohex(pthread_t tid) { char buffer[128]; snprintf(buffer,sizeof(buffer),0x%lx,tid); return buffer; } void InitThreadname(ThreadData*td,int i) { td-threadnamethreadto_string(i); } void*threadRoutine(void*args) { ThreadData*tdstatic_castThreadData*(args); int i0; while(i2) { coutpid: getpid(), tid : Tohex(pthread_self()), threadname: td-threadname test_i: test_iendl; sleep(1); i; test_i; } delete td; return nullptr; } int main() { vectorpthread_t tids; for(int i0;iNUM;i) { pthread_t tid; //这样子写是不可以的理论上面这个是在主线程创建的所以还是创建是在主线程的栈上面for循环结束了也就销毁了 //ThreadData td; ThreadData*tdnew ThreadData;//创建在堆上面每次创建都访问的是不同的堆空间这样子每一个线程都原来属于自己的堆空间 InitThreadname(td,i); pthread_create(tid,nullptr,threadRoutine,td); tids.push_back(tid); } for(int i0;itids.size();i) { pthread_join(tids[i],nullptr); } }运行结果可以看到所有的线程都是对全局变量进行操作像这种全局变量会被多个资源访问到那么这个变量就可以称为是被多个线程共享的‘共享资源’。3.__thread关键字两个___thread是GCC编译器内置的关键字正式名称叫线程局部存储Thread-Local StorageTLS使用__thread修饰的变量会在每一个线程中有一个独立的副本。ps这个是编译器内置的关键字所以只能修饰内置类型不能修饰自定义类型。#include iostream #include pthread.h #include unistd.h #include vector using namespace std; #define NUM 8 __thread int test_i0; struct ThreadData { string threadname; }; string Tohex(pthread_t tid) { char buffer[128]; snprintf(buffer,sizeof(buffer),0x%lx,tid); return buffer; } void InitThreadname(ThreadData*td,int i) { td-threadnamethreadto_string(i); } void*threadRoutine(void*args) { ThreadData*tdstatic_castThreadData*(args); int i0; while(i2) { coutpid: getpid(), tid : Tohex(pthread_self()), threadname: td-threadname test_i: test_iendl; sleep(1); i; test_i; } delete td; return nullptr; } int main() { vectorpthread_t tids; for(int i0;iNUM;i) { pthread_t tid; //这样子写是不可以的理论上面这个是在主线程创建的所以还是创建是在主线程的栈上面for循环结束了也就销毁了 //ThreadData td; ThreadData*tdnew ThreadData;//创建在堆上面每次创建都访问的是不同的堆空间这样子每一个线程都原来属于自己的堆空间 InitThreadname(td,i); pthread_create(tid,nullptr,threadRoutine,td); tids.push_back(tid); } for(int i0;itids.size();i) { pthread_join(tids[i],nullptr); } }运行结果可以发现确实在每一个线程中都单独存在了一个变量并且只对自己的线程中的变量进行操作。4. 线程访问其他线程的栈上面我们提到了在线程中是没有秘密的如果一个线程想要获取到其他线程的数据是可以做到的这里我们定义一个全局变量在主线程中对线程5的i值进行改变这样子线程5在while循环中只会打印两次其他线程则会打印3次。示例代码#include iostream #include pthread.h #include unistd.h #include vector using namespace std; #define NUM 8 int *pnullptr; struct ThreadData { string threadname; }; string Tohex(pthread_t tid) { char buffer[128]; snprintf(buffer,sizeof(buffer),0x%lx,tid); return buffer; } void InitThreadname(ThreadData*td,int i) { td-threadnamethread-to_string(i); } void*threadRoutine(void*args) { ThreadData*tdstatic_castThreadData*(args); int i0; if(td-threadnamethread-5) { pi; } while(i3) { coutpid: getpid(), tid : Tohex(pthread_self()), threadname: td-threadnameendl; sleep(1); i; } delete td; return nullptr; } int main() { vectorpthread_t tids; for(int i0;iNUM;i) { pthread_t tid; //这样子写是不可以的理论上面这个是在主线程创建的所以还是创建是在主线程的栈上面for循环结束了也就销毁了 //ThreadData td; ThreadData*tdnew ThreadData;//创建在堆上面每次创建都访问的是不同的堆空间这样子每一个线程都原来属于自己的堆空间 InitThreadname(td,i); pthread_create(tid,nullptr,threadRoutine,td); tids.push_back(tid); } sleep(2); *p2; for(int i0;itids.size();i) { pthread_join(tids[i],nullptr); } }运行结果5. 线程分离创建一个线程就是创建一个PCB所以对于线程来说主线程也是要等待其他线程的但是如果线程一直不退出那主线程不是就一直卡住了吗如果主线程要去做其他的事情不就也做不了了。如果我们对于线程的退出结果并不关心就可以让操作系统帮我们管理线程线程执行完了直接退出由操作系统来释放该资源。#include pthread.h int pthread_detach(pthread_t thread);thread参数线程的tid。代码示例1主线程在创建线程完成后分离线程但是不退出最后我们应该通过监控脚本可以看到3秒后只剩下主线程还在运行其他线程已经退出被操作系统释放。#include iostream #include pthread.h #include unistd.h #include vector using namespace std; #define NUM 8 struct ThreadData { string threadname; }; string Tohex(pthread_t tid) { char buffer[128]; snprintf(buffer,sizeof(buffer),0x%lx,tid); return buffer; } void InitThreadname(ThreadData*td,int i) { td-threadnamethread-to_string(i); } void*threadRoutine(void*args) { ThreadData*tdstatic_castThreadData*(args); int i0; while(i3) { coutpid: getpid(), tid : Tohex(pthread_self()), threadname: td-threadnameendl; sleep(1); i; } delete td; return nullptr; } int main() { vectorpthread_t tids; for(int i0;iNUM;i) { pthread_t tid; //这样子写是不可以的理论上面这个是在主线程创建的所以还是创建是在主线程的栈上面for循环结束了也就销毁了 //ThreadData td; ThreadData*tdnew ThreadData;//创建在堆上面每次创建都访问的是不同的堆空间这样子每一个线程都原来属于自己的堆空间 InitThreadname(td,i); pthread_create(tid,nullptr,threadRoutine,td); tids.push_back(tid); } for(int i0;itids.size();i) { pthread_detach(tids[i]); } while(true) {} return 0; }运行结果示例代码2线程自己也可以获取到自己的tid所以也可以在线程内部调用pthread_detach让线程分离。#include iostream #include pthread.h #include unistd.h #include vector using namespace std; #define NUM 8 struct ThreadData { string threadname; }; string Tohex(pthread_t tid) { char buffer[128]; snprintf(buffer,sizeof(buffer),0x%lx,tid); return buffer; } void InitThreadname(ThreadData*td,int i) { td-threadnamethread-to_string(i); } void*threadRoutine(void*args) { pthread_detach(pthread_self()); ThreadData*tdstatic_castThreadData*(args); int i0; while(i3) { coutpid: getpid(), tid : Tohex(pthread_self()), threadname: td-threadnameendl; sleep(1); i; } delete td; return nullptr; } int main() { vectorpthread_t tids; for(int i0;iNUM;i) { pthread_t tid; //这样子写是不可以的理论上面这个是在主线程创建的所以还是创建是在主线程的栈上面for循环结束了也就销毁了 //ThreadData td; ThreadData*tdnew ThreadData;//创建在堆上面每次创建都访问的是不同的堆空间这样子每一个线程都原来属于自己的堆空间 InitThreadname(td,i); pthread_create(tid,nullptr,threadRoutine,td); tids.push_back(tid); } // for(int i0;itids.size();i) // { // pthread_detach(tids[i]); // } while(true) {} return 0; }示例代码3如果让线程等待了又分离线程会怎么样呢#include iostream #include pthread.h #include unistd.h #include vector using namespace std; #define NUM 8 struct ThreadData { string threadname; }; string Tohex(pthread_t tid) { char buffer[128]; snprintf(buffer,sizeof(buffer),0x%lx,tid); return buffer; } void InitThreadname(ThreadData*td,int i) { td-threadnamethread-to_string(i); } void*threadRoutine(void*args) { // pthread_detach(pthread_self()); ThreadData*tdstatic_castThreadData*(args); int i0; while(i3) { coutpid: getpid(), tid : Tohex(pthread_self()), threadname: td-threadnameendl; sleep(1); i; } delete td; return nullptr; } int main() { vectorpthread_t tids; for(int i0;iNUM;i) { pthread_t tid; //这样子写是不可以的理论上面这个是在主线程创建的所以还是创建是在主线程的栈上面for循环结束了也就销毁了 //ThreadData td; ThreadData*tdnew ThreadData;//创建在堆上面每次创建都访问的是不同的堆空间这样子每一个线程都原来属于自己的堆空间 InitThreadname(td,i); pthread_create(tid,nullptr,threadRoutine,td); tids.push_back(tid); } for(int i0;itids.size();i) { pthread_join(tids[i],nullptr); } for(int i0;itids.size();i) { pthread_detach(tids[i]); } return 0; }运行结果会出现段错误的问题显然分离和等待只能二选一。ps线程分离也就是获取到了pthread库中存储的线程描述符tcb的起始地址tcb中有一个字段表示该线程是否分离将其改为1表示分离状态。

相关新闻

AI核心知识86——大语言模型之 Superalignment(简洁且通俗易懂版)

AI核心知识86——大语言模型之 Superalignment(简洁且通俗易懂版)

超级对齐 (Superalignment) 是 AI 安全领域中难度最高、最紧迫、也是最终极的课题。 如果说 普通对齐 是为了解决“如何让 GPT-4 听人类的话”; 那么 超级对齐 就是为了解决“当 AI 比人类聪明 100 倍时,人类如何控制它?” 这是由 OpenAI 前…

2026/7/6 13:10:08 阅读更多 →
Matlab【独家原创】基于TCN-BiGRU-SHAP可解释性分析的分类预测

Matlab【独家原创】基于TCN-BiGRU-SHAP可解释性分析的分类预测

目录 1、代码简介 2、代码运行结果展示 3、代码获取 1、代码简介 (TCN-BiGRUSHAP)基于时间卷积网络结合双向门控循环单元的数据多输入单输出SHAP可解释性分析的分类预测模型 由于TCN-BiGRU在使用SHAP分析时速度较慢,程序中附带两种SHAP的计算文件(正常版和提速…

2026/7/5 7:35:12 阅读更多 →
Matlab【独家原创】基于TCN-BiLSTM-SHAP可解释性分析的分类预测

Matlab【独家原创】基于TCN-BiLSTM-SHAP可解释性分析的分类预测

目录 1、代码简介 2、代码运行结果展示 3、代码获取 1、代码简介 (TCN-BiLSTMSHAP)基于时间卷积网络结合双向长短期记忆神经网络的数据多输入单输出SHAP可解释性分析的分类预测模型 由于TCN-BiLSTM在使用SHAP分析时速度较慢,程序中附带两种SHAP的计算文件(正常…

2026/5/17 2:30:45 阅读更多 →

最新新闻

ICM-42688-P与PIC24HJ256GP610在运动控制中的高效协同

ICM-42688-P与PIC24HJ256GP610在运动控制中的高效协同

1. ICM-42688-P与PIC24HJ256GP610的黄金组合解析在工业自动化和机器人控制领域,传感器与微控制器的协同工作能力直接决定了系统性能的上限。ICM-42688-P作为TDK InvenSense推出的6轴MEMS运动传感器,与Microchip的PIC24HJ256GP610微控制器形成的技术组合&…

2026/7/6 13:07:53 阅读更多 →
STM32与TPAFE0808实现多通道信号采集方案解析

STM32与TPAFE0808实现多通道信号采集方案解析

1. 项目背景与核心需求在工业自动化、医疗设备和精密仪器领域,多通道信号采集与系统监测一直是关键的技术挑战。传统方案往往需要复杂的模拟前端电路和多个分立元件,不仅增加了系统复杂度,还容易引入噪声和漂移问题。TPAFE0808这款8通道可编程…

2026/7/6 13:07:53 阅读更多 →
Unity MyFramework:框架里的代码简化技巧(三)

Unity MyFramework:框架里的代码简化技巧(三)

前两篇写了 MyFramework 里一些常用的代码简化技巧。 这一篇继续写第三组。 不过这次只写真正能让调用侧代码变短的东西。 也就是一眼能看到: 原本要写几行,现在一行就能表达清楚。 这类工具不是复杂系统。 它们更多是项目长期开发中沉淀出来的小函…

2026/7/6 13:03:49 阅读更多 →
终极指南:用DistroAV实现专业NDI网络音视频传输的完整方案

终极指南:用DistroAV实现专业NDI网络音视频传输的完整方案

终极指南:用DistroAV实现专业NDI网络音视频传输的完整方案 【免费下载链接】obs-ndi DistroAV (formerly OBS-NDI): NDI integration for OBS Studio 项目地址: https://gitcode.com/gh_mirrors/ob/obs-ndi DistroAV(原名OBS-NDI)是一…

2026/7/6 13:03:49 阅读更多 →
AD 23 与 AutoCAD 2024 协同:DXF 板框导入的 5 项预处理与 1 个精度保障技巧

AD 23 与 AutoCAD 2024 协同:DXF 板框导入的 5 项预处理与 1 个精度保障技巧

AD 23与AutoCAD 2024高效协同:DXF板框导入的预处理全流程与精度控制实战在硬件开发领域,PCB工程师与结构工程师的协同效率直接影响产品开发周期。当结构工程师使用AutoCAD 2024完成机箱设计后,如何确保其提供的DXF文件能够精准导入Altium Des…

2026/7/6 12:57:42 阅读更多 →
测试转大模型:AI 测试工程师的能力跃迁,把学习路线落到项目证据

测试转大模型:AI 测试工程师的能力跃迁,把学习路线落到项目证据

《测试转大模型:AI 测试工程师的能力跃迁,把学习路线落到项目证据》看起来是个大话题,但真落到项目里,常常就是几个具体选择。下面我尽量按实际开发时会遇到的问题来讲。摘要这篇面向想进入 AI 测试和质量工程方向的软件测试工程师…

2026/7/6 12:55:41 阅读更多 →

日新闻

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2 与 MySQL 单元测试兼容性:5 个关键 SQL 语句差异与规避方案

H2与MySQL单元测试兼容性:5个关键SQL语句差异与规避方案1. 单元测试中的数据库兼容性挑战在Java开发领域,单元测试是保证代码质量的重要环节。当应用涉及数据库操作时,测试环境的搭建往往成为开发者的痛点。H2数据库因其轻量级、内存模式和快…

2026/7/6 0:01:17 阅读更多 →
Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘

Windows任务栏终极清理指南:用RBTray一键隐藏窗口到系统托盘 【免费下载链接】rbtray A fork of RBTray from http://sourceforge.net/p/rbtray/code/. 项目地址: https://gitcode.com/gh_mirrors/rb/rbtray 你是否厌倦了Windows任务栏上密密麻麻的图标&…

2026/7/6 0:01:17 阅读更多 →
Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C++ 运行时库一键安装终极指南:告别DLL缺失烦恼

Visual C 运行时库一键安装终极指南:告别DLL缺失烦恼 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾经遇到过这样的情况:下载了…

2026/7/6 0:05:19 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/6 8:11:50 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/6 8:11:52 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/6 6:52:56 阅读更多 →

月新闻