自学嵌入式第N+1天(Linux篇——线程)

发布时间:2026/10/29 1:48:49

自学嵌入式第N+1天(Linux篇——线程) 上一篇讲了进程我们知道了进程的创建过程就是复制他的父进程以此来提高他的并发。那么进程和线程有啥区别呢进程是重量级线程资源分配的基本(最小)单位更侧重成为一个资源分配的单位线程轻量级进程线程是CPU的基本调度单位线程侧重于成为一个执行体 执行单位进程组成 pcb [text|data|bss|堆|栈]线程组成 线程ID 程序计数器 一组相关寄存器 栈空间 由于其他几个所占内存都非常小栈空间比他们大很多所以线程就是就约等于栈空间大小线程是CPU使用的基本单元它由线程ID、程序计数器、寄存器集合和栈组成。它与属于同一进程的其他线程共享代码段、数据段和其他操作系统资源如打开文件和信号。一个传统重量级的进程只有单个控制线程如果进程有多个控制线程那么它能同时做多个任务。代码实现1.线程创建int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);功能创建一个线程参数: thread为线程IDattr为线程属性NULL为默认属性也就是可结合属性还有可分离属性后面再讲start_routine 线程可执行函数 arg 给线程执行函数的参数 。void * start_thread (void *arg){//完成线程执行功能的}参数:arg是由pthread_create最后一个参数传递过来的返回值:void * 返回一个指针返回值:成功 0失败 返回error number不是之前的errno这里需要将自己手动赋值即errno返回值注意:线程共用的是进程空间资源共享如果操作同一个资源相互之间会影响线程之间关系是对等不存在进程间父子关系查看线程的命令:ps -eLf2.执行函数就是创建线程的第三个参数3.退出1void pthread_exit(void *retval);功能:结束调用线程参数:retval表示线程要带出的值也就是状态值注意:如果想要获得 该线程的 退出状态值则需要另外的线程 通过pthread_join来获取pthread_exit 传递的是退出状态值 对应的一块空间的地址pthread_join 接受的是这个地址注意:如果是在main线程中调用 pthread_exit()此时只是将主线程的执行结束了但不是整个进程结束了。要等所有子线程都执行结束进程的空间才会销毁。2int pthread_join(pthread_t thread, void **retval);功能:等待线程结束并回收线程资源参数:thread是要等待的线程的tidretval是获取退出状态值的参数返回值:成功 返回0失败返回错误码。3int pthread_cancel(pthread_t thread);功能向同一进程内的目标线程发送取消请求。只是发请求不会立刻杀死线程目标线程什么时候退出由线程自身的取消属性决定默认等到取消点sleep/read/pthread_mutex_lock/printf 等阻塞函数才响应参数thread目标线程的pid号返回值成功返回0失败返回错误码。下面用一个例子来演示上面几个函数创建两个线程一个线程复制文件前一半一个线程复制后一半。#include stdio.h #include unistd.h #include pthread.h #include fcntl.h #include sys/stat.h typedef struct { int fd_s; int fd_d; int size; }msg_t;//方便给执行函数传参 void * do_cp1(void *arg) { msg_t *p arg; lseek(p-fd_s,0,SEEK_SET); lseek(p-fd_d,0,SEEK_SET); char buf[p-size/2]; int ret read(p-fd_s,buf,sizeof(buf)); write(p-fd_d,buf,ret); return NULL; } //这里需要注意读写指针的位置在文件编程的时候说过 void * do_cp2(void *arg) { msg_t *p arg; lseek(p-fd_s,p-size/2,SEEK_SET); lseek(p-fd_d,p-size/2,SEEK_SET); char buf[p-size -p-size/2]; int ret read(p-fd_s,buf,sizeof(buf)); write(p-fd_d,buf,ret); return NULL; } void cleanup(void *arg) { msg_t *p arg; close(p-fd_s); close(p-fd_d); printf(---close---file\n); } int main(int argc, const char *argv[]) { int fd_s open(argv[1],O_RDONLY); int fd_d open(argv[2],O_WRONLY|O_TRUNC|O_CREAT,0666); if (fd_s 0 || fd_d 0) { perror(open fail); return -1; } struct stat st; if (stat(argv[1],st) 0) { perror(stat fail); return -1; } msg_t m; m.size st.st_size; m.fd_s fd_s; m.fd_d fd_d; pthread_t tid[2]; int ret pthread_create(tid[0],NULL,do_cp1,m); if (ret ! 0) { perror(pthread_create fail); return -1; } ret pthread_create(tid[1],NULL,do_cp2,m); if (ret ! 0) { perror(pthread_create fail); return -1; } pthread_cleanup_push(cleanup,m); pthread_join(tid[0],NULL); pthread_join(tid[1],NULL); pthread_exit(NULL); pthread_cleanup_pop(0); return 0; }4退出清理函数a.void pthread_cleanup_push(void (*routine)(void *) void *arg);功能注册一个线程清理函数参数routine是线程清理函数的入口arg是清理函数的参数。b.void pthread_cleanup_pop(int execute);功能调用清理函数参数execute为非0 执行清理函数为0不执行清理只有在push 之后、pop 之前线程执行pthread_exit() 被pthread_cancel()取消且走到取消点才会执行cleanup函数5设置线程属性设置分离属性目的是让线程消亡自动回收空间。a.int pthread_attr_init(pthread_attr_t *attr);功能初始化一个attr的变量参数attr需要变量来接受初始值返回成功返回0错误返回非0 b.int pthread_attr_destroy(pthread_attr_t *attr);功能销毁attr变量。参数attr属性变量返回成功返回错误返回非0 c.int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);功能把一个线程设置成相应的属性参数attr属性变量有init函数初始化他detachstate有2个可选值PTHREAD_CREATE_DETACHED 使用该属性创建的线程为分离态。PTHREAD_CREATE_JOINABLE 使用该属性创建的线程为可汇合态。返回值成功返回0失败返回非0d.int pthread_detach(pthread_t thread);功能设置分离属性参数线程id号填自己的id返回值成功返回0失败返回非0这里是两个设置分离属性的方法具体区别如下对比项pthread_attr_setdetachstatepthread_detach调用时机pthread_create 之前设置 attr 属性pthread_create 之后调用作用对象还未创建的线程模板属性已经存在、正在运行的线程使用流程①attr_init → ②setdetachstate → ③pthread_create(attr) → ④attr_destroy①pthread_create → ②传入 tid 调用 pthread_detach (tid)能不能设置 JOINABLE两种都能设置分离 / 可汇合只能设置成分离态不能改回可汇合典型场景批量创建一批线程统一全部设为分离态线程运行中途动态设置分离线程内部pthread_detach(pthread_self())限制只对本次用这个 attr 创建的线程生效一旦 detach 之后不能再 pthread_join 这个线程6子线程的回收注意如果预估子线程可以有限范围内结束则正常用pthread_join等待回收。如果预估子线程可能休眠或者阻塞则等待一定时间后强制回收。如果子线程已知必须长时间运行则不再回收其资源。就设置为分离属性。a.pid_t wait (int *wstatus)头文件#includesys/types.h #includesys/wait.h功能等待子进程状态发生改变子进程结束子进程被暂停子进程被恢复可以阻塞等待任意子进程退出并回收该进程的资源和获取退出状态值。用于父进程回收子进程。参数传一个int变量地址内核会把子进程退出信息填到这个变量里。WIFEXITED(status)子进程是否正常退出WEXITSTATUS(status)拿到子进程 main return /exit () 返回值WIFSIGNALED(status):判断是否是信号结束WTERMSTG(status):是哪个信号结束返回值成功返回回收子进程的pid号失败返回-1当不关心子进程状态是可以用waitNULLb. pid_t waitpid(pid_t pid, int *wstatus, int options);功能和wait一样但是可以选择是否阻塞等待。参数wstatus和wait一样pid 值含义pid 0只等待PID 等于该值的那一个子进程pid 0等待同进程组的任意子进程pid -1等待任意一个子进程等价于wait()pid -1等待指定进程组内任意子进程取绝对值为进程组 IDoptions为0时是阻塞等待为WNOHANG是非阻塞等待返回值成功时返回回收子进程的pid号失败时返回-1非阻塞时返回0表示没有任何子进程状态改变。waitpid(-1,status,0)等价于waitstatus。
延伸阅读

更多相关文章

2026/10/29 1:43:49

UVa 746 Polygon Visibility

题目描述 给定两个互不相交的凸多边形(非退化),多边形顶点按顺时针顺序给出。需要求平面上所有点 PPP( PPP 不在第一个多边形内部)的集合,使得存在 QQQ 属于第二个多边形,且线段 PQ‾\overline{…

2026/10/29 4:28:58

Hyperframes:HTML+CSS+MP4协同渲染范式

1. “hyperframes”不是新框架,而是对HTML/CSS/MP4协同渲染范式的重新命名最近在多个前端技术社区和CLI工具讨论区里,“hyperframes”这个词突然高频出现。它既不像React、Vue那样有明确的GitHub仓库和文档站,也不像Tailwind CSS那样自带配置…

2026/10/29 4:28:58

产品经理核心竞争力解析与能力提升路径

1. 产品经理的角色定位与能力图谱产品经理这个岗位最早起源于快消品行业,后来被科技公司引入并赋予了新的内涵。在互联网和数字化时代,产品经理已经成为一个集商业思维、用户洞察和技术理解于一体的复合型角色。不同于项目经理专注于执行交付&#xff0c…

2026/10/29 4:28:58

营销技能体系化训练:从用户洞察到实战复盘的完整路径

我一直觉得“marketingskills”这个标题特别像一张空白地图——谁都知道营销很重要,但真让你说清楚“到底要练哪些技能、按什么顺序练、练到什么程度算过关”,大多数人会卡住。我入行前八年基本都是被项目推着走,今天要写公众号就学排版&…

2026/10/29 4:28:58

hyperframes:MP4转HTML/CSS动效的CLI工具链

1. 项目概述:Hyperframes 不是“超帧”,而是一套面向现代网页动效交付的轻量级 CLI 工具链 你最近在 GitHub Trending 或前端技术群聊里一定见过 hyperframes 这个词——它既不是浏览器新 API,也不是某个框架的插件,更不是视频…

2026/10/29 4:28:58

解决VSCode中Python虚拟环境PowerShell执行策略问题

1. 问题现象与背景分析最近在VSCode中使用Python虚拟环境时,遇到了一个典型的PowerShell执行策略问题。当尝试运行.\venv\Scripts\Activate.ps1激活虚拟环境时,系统抛出错误:"无法加载文件...因为在此系统上禁止运行脚本"。这个错误…

2026/10/29 4:23:58

DeepSeek本地部署全流程:显存、CUDA环境与4-bit量化

简介:这份PDF文档聚焦DeepSeek大模型的本地化部署,面向希望私有化运行开源模型的企业开发者、运维人员及具备一定Linux与深度学习基础的个人研究者,帮助其在数据安全、定制化需求和算力规划之间建立可落地的配置方案。包内仅含1个PDF文件&…

2026/10/28 14:42:12

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/28 15:28:56

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/28 3:32:29

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/29 0:03:42

学生选课系统DFD图绘制指南:边界划分与分层校验实战

简介:文档以顶层与第一层DFD图为核心,完整刻画学生选课系统的逻辑模型,面向软件工程课程设计、系统分析学习及毕设前期建模人群。顶层图界定系统边界,外部实体包括管理员、教师和学生三类角色;第一层图进一步细化用户登…

2026/10/29 0:03:42

JIRA敏捷落地:Scrum角色权限、Sprint与燃尽图避坑指南

简介:围绕“基于JIRA的敏捷开发项目管理”这一主题,面向产品负责人、Scrum Master及研发测试成员,梳理Scrum角色分工、迭代流程与JIRA工具配置的对应关系,适合初、中级团队导入敏捷管理时参考。压缩包共1个docx文件,大…

2026/10/29 0:03:42

SEMI S8人机工程验收实战:从条款拆解到现场实测的完整指南

简介:面向半导体设备设计、制造与运维工程师及安全合规人员,这份资料聚焦SEMI标准体系下的设备安全规范,重点收录SEMI S8-0308《半导体制造设备人体工程学工程安全指南》。内容围绕设备设计原则、错误与事故预防、人体工程学适配三大主线展开…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑