自学嵌入式第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 3:13:54

雷达基数据解析:定长径向块与字节偏移的底层逻辑

简介:面向气象数据处理、雷达产品开发与教学科研人员的CINRAD雷达基数据格式参考文档,聚焦SA/SB与CA/CB两类雷达,帮助读者厘清二进制基数据的存储与解析规则,适合需要编写解码程序或核对字段含义的初中级开发者查阅。压缩包内为1个…

2026/10/29 3:13:54

轻量级视觉Transformer在温室害虫识别中的应用与优化

1. 项目背景与核心价值在温室农业环境中,害虫早期识别一直是困扰种植者的难题。传统的人工巡查方式效率低下,而基于深度学习的视觉识别系统往往需要昂贵的计算设备。这个项目提出了一种轻量级视觉Transformer网络,专门针对温室环境中的害虫识…

2026/10/29 3:13:54

正余弦优化算法(SCA)改进与应用实践

1. 正余弦优化算法(SCA)的核心原理与演进背景正余弦优化算法(Sine Cosine Algorithm, SCA)作为一种新兴的群体智能优化方法,其灵感来源于数学中的正弦和余弦函数在空间中的周期性波动特性。该算法最早由Mirjalili在201…

2026/10/29 3:13:54

Kibana安装与豆包日志分析实战指南

1. 豆包 Kibana 安装环境准备Kibana作为Elastic Stack的数据可视化组件,在豆包生态中承担着日志分析和监控数据展示的重要角色。在开始安装前,我们需要确保基础环境符合要求。我建议使用Linux系统进行部署,这里以Ubuntu 20.04 LTS为例说明环境…

2026/10/29 3:13:54

顽固程序强制卸载与残留清理全攻略:从卸不掉到卸干净

1. 为什么“删了”和“删干净”是两码事很多人以为把桌面图标拖进回收站、或者在控制面板里点一下“卸载”,软件就从电脑里消失了。我见过太多机器,表面上干干净净,一查C盘空间还是红的,注册表里躺着一堆孤儿键值,开机…

2026/10/29 3:08:54

语义分割中mIoU与边界F-score的协同优化指南

1. 为什么这两个指标总让人“算得准、看不懂、调不动”?在语义分割项目里,我见过太多人把模型训练完,往验证集上一跑,mIoU 78.3%,边界 F-score 62.1%,然后就心满意足地合上笔记本——结果部署到产线摄像头里…

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
免费获取方案
☎咨询二维码 ☎ ↑