当前位置: 首页 > article >正文

【Linux开发】01多线程编程:线程的创建与运行

一、为什么需要线程1.1 回顾多进程的缺点我们之前学习了多进程服务器父进程fork出子进程来处理客户端请求。这种方式虽然能实现并发但存在一些问题资源开销大每个进程都有独立的地址空间创建和切换进程的成本较高。通信麻烦进程间通信IPC需要管道、共享内存等机制比较繁琐。数据共享困难父子进程虽然 fork 时复制了数据但之后各自独立要共享数据必须用 IPC。1.2 线程的优势线程Thread是进程内的一个执行流它共享进程的地址空间代码段、数据段、堆等但拥有独立的栈和寄存器上下文。对比项进程线程地址空间独立共享除了栈创建开销大小切换开销大小数据共享需要 IPC直接访问全局变量并发性多进程可多核多线程也可多核稳定性一个进程崩溃不影响其他一个线程崩溃可能导致整个进程崩溃因此在需要大量并发且频繁共享数据的场景下如 Web 服务器、GUI 程序线程是更合适的选择。二、线程的基本概念线程 ID每个线程有一个唯一的标识符pthread_t类型类似于进程的 PID。线程主函数线程开始执行的地方函数原型为void* thread_func(void* arg)。线程的终止线程函数返回、调用pthread_exit()或被取消。线程的回收类似进程的wait需要调用pthread_join等待线程结束并回收资源否则可能造成僵尸线程类似僵尸进程。三、创建线程pthread_create3.1 函数原型#includepthread.hintpthread_create(pthread_t*thread,constpthread_attr_t*attr,void*(*start_routine)(void*),void*arg);thread输出参数成功时返回新线程的 ID。attr线程属性如栈大小、调度策略通常传NULL表示使用默认属性。start_routine线程主函数指针格式必须为void* func(void*)。arg传递给线程主函数的参数可以是任意指针。返回值成功返回 0失败返回非零错误码不是 -1。3.2 线程主函数格式void*my_thread_func(void*arg){// 线程执行的代码return(void*)some_ptr;// 返回值可以通过 pthread_join 获得}3.3 参数传递由于arg是void*可以传递任意类型传递基本类型将值强转为void*注意数据长度。传递结构体传结构体指针。传递多个参数封装成结构体。四、等待线程结束pthread_join4.1 为什么需要 join主线程结束时会终止整个进程所有子线程也会被强制结束。为了避免主线程过早退出需要等待子线程完成。同时可以获取子线程的返回值并回收线程资源防止资源泄漏。4.2 函数原型intpthread_join(pthread_tthread,void**retval);thread要等待的线程 ID。retval二级指针用于接收线程主函数的返回值如果不需要可传NULL。返回值成功返回 0失败返回错误码。4.3 注意pthread_join会阻塞调用线程直到目标线程终止。一个线程只能被 join 一次多次 join 行为未定义。如果线程已经终止pthread_join会立即返回。五、完整示例创建线程并等待返回值下面是一个完整的示例主线程创建一个子线程子线程循环打印消息最后返回一个字符串主线程打印该字符串并释放内存。#includestdio.h#includestdlib.h#includestring.h#includepthread.h#includeunistd.h// 线程主函数void*thread_main(void*arg){inti;intcnt*((int*)arg);// 获取传入的参数循环次数char*msg(char*)malloc(sizeof(char)*50);strcpy(msg,Hello, Im thread~ \n);for(i0;icnt;i){sleep(1);// 模拟耗时工作puts(running thread);}return(void*)msg;// 返回字符串指针}intmain(){pthread_tt_id;intthread_param5;void*thr_ret;// 1. 创建线程if(pthread_create(t_id,NULL,thread_main,(void*)thread_param)!0){perror(pthread_create);return-1;}// 2. 等待线程结束并获取返回值if(pthread_join(t_id,thr_ret)!0){perror(pthread_join);return-1;}// 3. 打印线程返回的消息printf(Thread return message: %s\n,(char*)thr_ret);free(thr_ret);// 释放线程内部分配的内存return0;}5.1 编译与运行由于pthread库不是默认链接的编译时需要加上-pthread选项gcc-pthreadthread_example.c-othread_example ./thread_example输出running thread running thread running thread running thread running thread Thread return message: Hello, Im thread~5.2 代码详解行号解释pthread_create(t_id, NULL, thread_main, (void*)thread_param)创建线程参数thread_param的地址传给线程函数。thread_main中的int cnt *((int*)arg)解引用获取传入的整数值。malloc分配字符串线程内部分配内存返回给主线程主线程负责释放。pthread_join(t_id, thr_ret)主线程等待子线程结束thr_ret接收返回值。free(thr_ret)释放子线程中malloc的内存避免内存泄漏。六、常见问题与注意事项6.1 编译时链接错误错误undefined reference to pthread_create原因未链接 pthread 库。解决编译时加上-pthread选项。6.2 主线程过早退出// 错误示例intmain(){pthread_ttid;pthread_create(tid,NULL,func,NULL);// 没有 pthread_join主线程直接退出 → 整个进程结束子线程被强制终止}解决调用pthread_join等待子线程或调用pthread_exit(NULL)让主线程退出而进程继续但通常不推荐。6.3 传递局部变量作为线程参数// 危险示例void*func(void*arg){int*p(int*)arg;printf(%d\n,*p);// p 指向的可能是主线程的局部变量但主线程可能已退出或变量失效}intmain(){intx10;pthread_create(tid,NULL,func,x);pthread_join(tid,NULL);// 这里 x 还在作用域内安全return0;}注意如果主线程在子线程使用参数之前就退出了或局部变量被销毁则子线程会访问无效内存。因此要么用pthread_join等待要么将参数放在堆上malloc。6.4 返回值内存管理线程主函数返回的指针通常指向静态数据或堆上分配的内存。如果返回局部变量的地址该内存在线程函数退出后会被释放造成悬空指针。最佳实践使用malloc分配返回值调用pthread_join的线程负责free。6.5 线程 ID 的类型pthread_t可能是一个整数或结构体不能直接当作整数打印除非用%lu并强制转换但不可移植。调试时可使用pthread_self()获取当前线程 ID并打印指针值。七、总结7.1 核心函数速查函数作用pthread_create(tid, NULL, func, arg)创建新线程pthread_join(tid, retval)等待线程结束并获取返回值pthread_self()获取当前线程的 IDpthread_exit(retval)主动终止当前线程类似return7.2 线程 vs 进程项目进程线程数据共享复杂需要 IPC简单直接访问全局变量创建/切换开销大小崩溃影响其他进程不受影响整个进程可能崩溃同步需求较少数据独立较多需锁保护共享数据

相关文章:

【Linux开发】01多线程编程:线程的创建与运行

一、为什么需要线程? 1.1 回顾多进程的缺点 我们之前学习了多进程服务器:父进程 fork 出子进程来处理客户端请求。这种方式虽然能实现并发,但存在一些问题: 资源开销大:每个进程都有独立的地址空间,创建和切…...

Matlab串口通信上位机开发:从零搭建实时数据采集系统(附完整代码)

Matlab串口通信上位机开发实战:从零构建工业级数据采集系统 在工业自动化、物联网设备调试和科研实验数据采集领域,串口通信作为最基础也最可靠的数据传输方式,至今仍发挥着不可替代的作用。Matlab凭借其强大的数值计算能力和丰富的可视化工具…...

LIME算法实战:从理论到应用的全面解析

1. 为什么我们需要LIME算法? 第一次接触LIME算法是在处理一个医疗影像分类项目时。当时我们的深度学习模型准确率高达95%,但医生们始终不敢完全信任这个"黑箱"。我记得有位老专家指着CT扫描图问我:"小伙子,你能告诉…...

Wireshark蓝牙协议抓包实战:从环境搭建到数据解析

1. 环境准备:硬件与软件双管齐下 搞蓝牙协议分析就像侦探破案,没有趁手的工具可不行。我去年调试智能手环时,就因为没配好环境浪费了两天时间。咱们先从必备装备说起: 硬件三件套缺一不可: nRF52840 Dongle&#xff1a…...

OpenClaw开发提效指南:Qwen3.5-9B实现日志分析+异常修复建议

OpenClaw开发提效指南:Qwen3.5-9B实现日志分析异常修复建议 1. 为什么开发者需要日志分析自动化 作为一名全栈开发者,我每天要面对数十个微服务的日志文件。传统的人工排查方式就像在黑暗森林中摸索——需要反复grep关键字、比对时间戳、手动拼接调用链…...

电能质量扰动仿真:MATLAB/Simulink的奇妙之旅

Power Quality Disturbance:基于MATLAB/Simulink的各种电能质量扰动仿真模型,包括配电线路故障、感应电机启动、变压器励磁、单相/三相非线性负载等模型,可用于模拟各种电能质量扰动和分析研究。 附带一份详细的说明文档对各模型进行说明&…...

解锁商场流量密码:一次地贴定制如何让我的活动效果翻倍?

在商场运营与活动营销中,流量获取与转化始终是核心痛点——高空广告成本高、受众触达不精准,传统海报易被忽略,线上引流又面临流量碎片化、转化链路长的困境。而商场地贴作为一种低成本、高触达、强引导的户外广告物料,往往被多数…...

Unity发布京东小游戏反

从 UI 工程师到 AI 应用架构者 13 年前,我的工作是让按钮在 IE6 上对齐; 13 年后,我用 fetch-event-source 订阅大模型的“思维流”,用 OCR 解锁图片中的文字——前端,正在成为 AI 产品的第一道体验防线。 最近&#x…...

MCP服务器架构设计图首次公开:含时序一致性保障机制、跨域设备注册拓扑、双向心跳状态机(2024 Q2最新LTS版)

第一章:MCP服务器架构设计图概览与核心设计哲学MCP(Modular Control Plane)服务器并非传统单体控制平面的简单重构,而是一种以“可插拔、可观测、可演进”为根基的分布式控制面架构。其设计图呈现清晰的分层结构:底层为…...

从SVM到LSTM:我的谣言检测模型优化踩坑实录(附PHEME/微博数据集对比)

从SVM到LSTM:我的谣言检测模型优化踩坑实录 去年夏天接手社交媒体谣言检测项目时,我完全没料到这个看似标准的文本分类任务会如此充满挑战。团队最初的想法很简单:用传统机器学习方法快速搭建基线,再逐步升级到深度学习模型。但当…...

小白/程序员必看:收藏这份强化学习训练智能体的实战指南(HelloAgents实战篇)

本文介绍了如何使用强化学习训练智能体,从LLM训练流程讲起,对比了PBRFT与Agentic RL的区别,并详细阐述了Agentic RL的六大核心能力:推理、工具使用、记忆、规划、自我改进和感知。文章还介绍了HelloAgents框架如何集成强化学习库T…...

APSIM模型---农田管理优化、作物品种和株型筛选、农田固碳和温室气体排放等

随着数字农业和智慧农业的发展,基于过程的农业生产系统模型在模拟作物对气候变化的响应与适应、农田管理优化、作物品种和株型筛选、农田固碳和温室气体排放等领域扮演着越来越重要的作用。APSIM (Agricultural Production Systems sIMulator)模型是世界知名的作物生…...

使用钉钉远程操作你的claude code露

先回顾:三次握手(建立连接)核心流程(实际版) 为了让挥手流程衔接更顺畅,咱们先快速回顾三次握手的实际核心,避免上下文脱节: 第一步(客户端→服务器)&#xf…...

我的前半生

大家好,我是李文涛。2026年,我步入了人生的不惑之年。回望来时路,快四十载光阴如白驹过隙。今天想和大家分享一下我的前半生——一个从秦岭深处走出的小镇青年,是如何一步步走到今天的。1、 在最美的地方,度过最纯真的…...

Java全栈开发工程师面试实录:从基础到高阶的深度技术探讨

Java全栈开发工程师面试实录:从基础到高阶的深度技术探讨 一、开场介绍 面试官(李工):你好,我是李工,目前在一家互联网大厂负责后端架构设计。今天来聊聊你的技术背景和项目经验。 应聘者(张伟&…...

基于贝叶斯优化的稀疏高斯过程回归(BO-SGPR)多输入单输出回归模型【MATLAB】

基于贝叶斯优化的稀疏高斯过程回归(BO-SGPR)多输入单输出回归模型【MATLAB】 在处理复杂的非线性回归、小样本学习以及带有不确定性量化的预测任务时,高斯过程回归(Gaussian Process Regression, GPR) 因其强大的理论基…...

Tun模式浏览器无法使用网络

环境Win11,v2软件表现情况打开Tun模式后发现无法连接网络,v2的dns配置保持默认。本文方法适用于打开Tun模式时,虚拟网卡可以正常创建,但是仍然无法联网的情况。在开始里搜索查看网络连接,这里是可以正常创建的。解决方…...

避坑指南:企业引入AI编程助手,选CodeGeex还是Copilot企业版?

企业级AI编程助手选型实战:CodeGeex与Copilot企业版的深度博弈 当技术决策者站在数字化转型的十字路口,选择一款适合企业长期发展的AI编程助手绝非简单的功能对比。这背后涉及数据主权、团队协作范式、技术债务管理等一系列战略考量。我们曾见证某金融科…...

AI 时代:祛魅、适应与重新定义宋

指令替换 项目需求:将加法指令替换为减法 项目目录如下 /MyProject ├── CMakeLists.txt # CMake 配置文件 ├── build/ #构建目录 │ └── test.c #测试编译代码 └── mypass2.cpp # pass 项目代码 一,测试代码示例 test.c // test.c #includ…...

视觉问答(VQA)前沿进展:5大创新数据集与顶会论文精要解析

1. 视觉问答(VQA)技术现状与挑战 视觉问答(VQA)作为计算机视觉与自然语言处理的交叉领域,近年来发展迅猛。简单来说,VQA就是让计算机看懂图片内容后,回答人类提出的自然语言问题。比如给出一张…...

财税合规数字化建设与税务师事务所行业实践

随着企业监管趋严与数字化不断深入,财税合规已成为企业经营管理中的重要环节。无论是中小企业还是集团公司,都需要建立规范的财务流程,完善纳税申报机制,强化风险自查能力,以实现合法合规,稳定经营。财税合…...

VL1_四选一多路器:从RTL设计到覆盖率验证的全流程解析

1. 四选一多路器的基本概念与应用场景 四选一多路器(4-to-1 Multiplexer)是数字电路设计中最基础的组合逻辑电路之一。简单来说,它就像一个智能开关,能够根据控制信号从四个输入信号中选择一个输出。这种电路在实际项目中应用非常…...

实时行情系统设计:从协议选择到高可用架构,再到数据源选型蘸

一、核心问题及解决方案(按踩坑频率排序) 问题 1:误删他人持有锁——最基础也最易犯的漏洞 成因:释放锁时未做身份校验,直接执行 DEL 命令删除键。典型场景:服务 A 持有锁后,业务逻辑耗时超过锁…...

CET中电技术如何助光伏企业在“四可“时代抢占先机?

2026年,"十五五"规划开局之年,新能源行业正经历一场深刻的变革。从2025年5月30日136号文推动投资主体转变,到2026年1月30日114号文将"四可"能力从试点推广期正式升级为政策强制标准,分布式光伏的并网逻辑已被…...

无侵入式Allegro许可证使用数据采集方案

无侵入式Allegro许可证使用收数据方案拿这些个年我跟各种许可证打交道,从最开始的Named User整到并发许可、角色绑定,真是踩过不少坑。你要是想解决阿里云、Enovia、3DEXPERIENCE这伙软件的许可证管理问题,传统方法要么成本高,要么…...

_EMD-KPCA-LSTM 基于经验模态分解和核主成分分析的长短期记忆网络多维时间序列预测_matlab_实现基于EMD-KPCA-LSTM多维时间序列预测模型,与LSTM和EMD-LSTM进行对比

EMD-KPCA-LSTM 基于经验模态分解和核主成分分析的长短期记忆网络多维时间序列预测MATLAB代码(含LSTM、EMD-LSTM、EMD-KPCA-LSTM三个模型的对比) matlab 参考文档:基于EMD-PCA-LSTM的光伏功率预测模型 研究内容:本案例使用数据集是…...

2.76亿|国网浙江电力 2026 年第一次物资框架采购成交候选人名单出炉

4月3日,国网浙江电力2026年第一次物资类框架协议竞争性谈判采购推荐的成交候选人名单公示(采购编号:ZBGW26-003),涵盖线路防雷、通信配件、量子加密模组、带电作业机器人附件等 23 类细分品类。中标总金额27552.5万元&…...

VMD 1.9.4实战:如何高效查看蛋白质-配体分子动力学模拟轨迹(附帧数优化技巧)

VMD 1.9.4实战:如何高效查看蛋白质-配体分子动力学模拟轨迹(附帧数优化技巧) 分子动力学模拟已成为研究蛋白质-配体相互作用的重要工具,而可视化分析则是理解模拟结果的关键环节。Visual Molecular Dynamics(VMD&#…...

实战复盘】游戏上市公司合同系统实施案例(六):被忽视的IT力量——为什么业务主导的项目更需要IT深度参与?

本文为《游戏上市公司合同系统实施案例》系列第六篇。 👉 (一)业务背景|(二)多维预算|(三)合同预警|(四)安全攻防|&#x…...

STM32 UART 通信详解

通用异步收发传输器(UART)是STM32微控制器中最基础、最常用的串行通信接口之一。它通过简单的两根信号线(TX和RX)实现全双工异步数据交换,广泛应用于与PC调试、传感器模块、蓝牙/Wi-Fi模块等的通信。一、UART协议基础1…...