二、线程操作
注意使用pthread系列函数编译时必须手动链接线程库gcc test.c-otest-pthread不加-pthread会出现编译 / 运行异常。为什么必须加-pthread-pthread不只是单纯链接-lpthread它同时做两件事链接阶段链接 libpthread 线程库提供 pthread_create / pthread_self / pthread_exit 等函数的实现编译预处理阶段定义宏、调整线程安全的标准库行为如 errno 线程局部存储、锁实现。线程操作(1)pthread_create函数1. 函数介绍1. 函数原型#includepthread.hintpthread_create(pthread_t*thread,constpthread_attr_t*attr,void*(*start_routine)(void*),void*arg);2. 返回值成功返回 0失败返回对应错误编号 (不是之前说的 errno 获取错误号信息strerror)*thread 数据无效。3. 参数pthread_t *thread输出参数创建成功后新线程 ID 会存入该指针指向内存创建失败时*thread 内容未定义。const pthread_attr_t *attr线程属性结构体指针非 NULL使用结构体中自定义属性创建线程结构体需先用pthread_attr_init()初始化NULL采用系统默认线程属性。void *(*start_routine)(void *)线程入口函数线程启动后执行该函数返回值为 void*。void *arg传递给入口函数start_routine的唯一参数。4. 作用在调用进程中创建并启动一条新线程。2. 样例 (创建一个子线程)准备一个 pthread_create.c 文件#includestdio.h#includestring.h#includepthread.h#includesys/types.h#includeunistd.hvoid*handle(void*arg){printf(子线程已创建...\n);printf(参数arg: %d\n,*(int*)arg);returnNULL;}intmain(){// 创建新线程pthread_tthread;intnum10;inttidpthread_create(thread,NULL,handle,(void*)num);if(tid!0){char*strstrerror(tid);printf(%s\n,str);}for(inti0;i3;i){printf(pid: %d, i: %d\n,getpid(),i);}sleep(1);return0;}注意上面的代码部分只有handle函数部分是子线程独立运行的代码段。(2)pthread_self函数1. 函数介绍1. 函数原型#includepthread.hpthread_tpthread_self(void);2. 参数无参数。3. 返回值该函数调用永远成功返回调用者线程的 ID类型为 pthread_t。4. 作用获取当前调用进程的 ID 。(3)pthread_exit函数1. 函数介绍1. 函数原型#includepthread.hvoidpthread_exit(void*retval);2. 参数retval线程退出返回值指针作用存放线程结束后要传递给其他线程的返回数据接收方式其他线程调用pthread_join(tid, res)res会接收该指针。取值规则若不需要返回数据传 NULL若要传递数据不能传入栈局部变量地址线程销毁后栈会释放内存失效建议传全局变量 / 堆内存地址3. 返回值函数无返回值调用后当前线程立刻终止代码不会回到调用 pthread_exit 的下一行继续执行。4. 作用终止一个线程在哪个线程中调用就表示终止哪个线程。2. 样例创建一个 pthread_exit.c 文件#includestdio.h#includestring.h#includepthread.h#includesys/types.h#includeunistd.hvoid*rollback(void*arg){printf(child thread id : %ld\n,pthread_self());returnNULL;}intmain(){// 创建新线程pthread_ttid;intarg10;intretpthread_create(tid,NULL,rollback,(void*)arg);if(ret!0){char*errstrstrerror(ret);printf(error : %s\n,errstr);}// 主线程for(inti1;i3;i){printf(i %d\n,i);}printf(tid: %ld, main thread id: %ld\n,tid,pthread_self());// 终止主线程pthread_exit(NULL);printf(main thread die...\n);return0;}可以看到 “main thread die…” 并没有输出因此可以得到终结线程后的代码将不会执行。(4)pthread_join函数1. 函数介绍1. 函数原型#includepthread.hintpthread_join(pthread_tthread,void**retval);2. 参数pthread_t thread待等待的目标线程 ID限制该线程必须是 joinable默认新建线程都是 joinable调用 pthread_detach 后不可 join。void **retval输出型二级指针用于接收目标线程的退出返回值传 NULL代表不需要接收线程退出结果非空会写入pthread_exit()传入的指针线程被取消则写入PTHREAD_CANCELED。3. 返回值成功返回 0失败返回对应错误编号。4. 作用该函数会阻塞等待参数thread指定的线程终止。2. 样例创建一个 pthread_join.c 文件#includestdio.h#includestring.h#includepthread.h#includesys/types.h#includeunistd.hintnum10;//这里一定要用全局变量(存在数据段)或者堆内存线程结束栈内存会被回收void*rollback(void*arg){printf(child thread id : %ld\n,pthread_self());sleep(3);// 测试pthread_join是否阻塞pthread_exit((void*)num);// 等同于(void *)num}intmain(){// 创建新线程pthread_ttid;intarg10;intretpthread_create(tid,NULL,rollback,(void*)arg);if(ret!0){char*errstrstrerror(ret);printf(error : %s\n,errstr);}// 主线程for(inti1;i3;i){printf(i %d\n,i);}printf(tid: %ld, main thread id: %ld\n,tid,pthread_self());// 阻塞等待回收子线程void*thread_val;pthread_join(tid,thread_val);printf(main thread rece: %d\n,*(int*)thread_val);// 终止主线程pthread_exit(NULL);printf(main thread die...\n);return0;}(5)pthread_detach函数1. 函数介绍1. 函数原型#includepthread.hintpthread_detach(pthread_tthread);2. 参数pthread_t thread目标线程 ID指定要设置为分离态的线程限制该线程当前必须是可汇合 (joinable) 状态不能已经被分离。3. 返回值成功返回 0失败返回对应错误编号。4. 作用修改线程属性为分离态改变资源回收规则默认新建线程是 joinable退出后资源残留必须pthread_join回收detach 之后线程一旦结束操作系统自动释放线程栈、线程管理结构体不会内存泄漏。解除 “必须等待” 的限制主线程无需阻塞等待该线程执行完毕二者完全异步运行。2. 样例创建一个 pthread_detach.c 文件#includestdio.h#includestring.h#includepthread.h#includesys/types.h#includeunistd.hintnum10;//这里一定要用全局变量(存在数据段)或者堆内存线程结束栈内存会被回收void*rollback(void*arg){printf(child thread id : %ld\n,pthread_self());sleep(3);// 测试pthread_detach是否阻塞return(void*)num;}intmain(){// 创建新线程pthread_ttid;intarg10;intretpthread_create(tid,NULL,rollback,(void*)arg);if(ret!0){char*errstrstrerror(ret);printf(error : %s\n,errstr);}// 主线程for(inti1;i3;i){printf(i %d\n,i);}printf(tid: %ld, main thread id: %ld\n,tid,pthread_self());// 设置子线程分离,子线程分离后子线程结束时对应的资源就不需要主线程释放retpthread_detach(tid);if(ret!0){char*errstrstrerror(ret);printf(error1 : %s\n,errstr);}// 设置分离后对分离的子线程进行连接 pthread_join()void*thread_val;retpthread_join(tid,thread_val);if(ret!0){char*errstrstrerror(ret);printf(error2 : %s\n,errstr);}printf(main thread rece: %d\n,*(int*)thread_val);// 终止主线程pthread_exit(NULL);printf(main thread die...\n);return0;}可以看到将线程分离后再次进行连接将会错误。(6)pthread_cancel函数1. 函数介绍1. 函数原型#includepthread.hintpthread_cancel(pthread_tthread);2. 参数pthread_t thread目标线程 ID代表要发送取消信号的线程支持对自身线程、其他线程发送取消请求。3. 返回值成功返回 0失败返回对应错误编号。4. 作用pthread_cancel()函数向thread指定的目标线程发送取消请求。目标线程是否响应、何时响应这个取消请求由该线程自身的两个属性控制state (取消使能状态) 和 type (取消类型)。5. 两大关键控制属性目标线程自身控制是否响应取消① 取消使能状态pthread_setcancelstate函数设置 statePTHREAD_CANCEL_ENABLE默认接收并处理取消请求PTHREAD_CANCEL_DISABLE忽略取消请求请求排队暂存直到重新开启。② 取消类型pthread_setcanceltype函数设置 typePTHREAD_CANCEL_DEFERRED默认延迟取消不会立刻终止仅在线程调用取消点函数read/write/pthread_join/sleep等系统 IO、同步函数时才触发取消流程业务计算循环、纯 CPU 运算代码段不会被中途打断安全。PTHREAD_CANCEL_ASYNCHRONOUS异步取消线程任意代码位置都可能被随时终止风险极高极易造成资源泄漏、死锁极少使用。6. 线程被取消后的固定执行流程逆序执行所有清理函数pthread_cleanup_push执行线程私有数据 TSD 析构函数线程正式终止退出。2. 样例创建一个pthread_cancel.c 文件#includestdio.h#includestring.h#includepthread.h#includesys/types.h#includeunistd.hintnum10;//这里一定要用全局变量(存在数据段)或者堆内存线程结束栈内存会被回收void*rollback(void*arg){printf(child thread id : %ld\n,pthread_self());sleep(1);for(inti1;i100;i){printf(child pthread i: %d\n,i);}return(void*)num;}intmain(){// 创建新线程pthread_ttid;intarg10;intretpthread_create(tid,NULL,rollback,(void*)arg);if(ret!0){char*errstrstrerror(ret);printf(error : %s\n,errstr);}// 设置子线程分离,子线程分离后子线程结束时对应的资源就不需要主线程释放pthread_detach(tid);// 终止指定子进程pthread_cancel(tid);for(inti1;i3;i){printf(i %d\n,i);}printf(tid: %ld, main thread id: %ld\n,tid,pthread_self());// 终止主线程pthread_exit(NULL);printf(main thread die...\n);return0;}可以看到子线程并没有输出循环体的内容就被父进程给终止了。这是因为sleep函数本身是取消点函数当取消请求队列中有取消信号则会终止该线程。线程属性线程属性类型pthread_attr_t。(1) 初始化、释放线程属性资源#includepthread.hintpthread_attr_init(pthread_attr_t*attr);intpthread_attr_destroy(pthread_attr_t*attr);描述pthread_attr_init()函数会使用默认值初始化attr指向的线程属性对象。调用该函数后可以通过配套系列函数单独修改属性对象里的各项配置之后该属性对象可以重复用于一次或多次pthread_create()创建线程。对一个已经初始化完成的属性对象再次调用pthread_attr_init()程序行为属于未定义。当线程属性对象不再使用时应当调用pthread_attr_destroy()销毁释放内部资源。销毁属性对象不会对以往依靠该属性创建出的线程产生任何影响。属性对象被销毁后可以再次调用pthread_attr_init()重新初始化复用对已经销毁、未重新初始化的属性对象做任何其他操作结果都是未定义行为。返回值两个函数调用成功均返回 0执行失败时返回非 0 错误码。(2) 设置、获取线程属性#includepthread.hintpthread_attr_getdetachstate(constpthread_attr_t*attr,int*detachstate);intpthread_attr_setdetachstate(pthread_attr_t*attr,intdetachstate);描述pthread_attr_setdetachstate()函数用于设置线程属性对象attr的分离状态属性参数detachstate指定目标状态。该属性决定了使用此属性对象创建出的线程默认是可汇合joinable还是分离detached 状态。detachstate仅支持以下两个宏取值PTHREAD_CREATE_DETACHED使用该属性创建的线程直接为分离态。PTHREAD_CREATE_JOINABLE使用该属性创建的线程为可汇合态。刚通过pthread_attr_init()初始化完成的线程属性对象分离状态默认值PTHREAD_CREATE_JOINABLE。pthread_attr_getdetachstate()函数会将属性对象attr中存储的分离状态存入detachstate指针指向的内存中返回。返回值两个函数调用成功均返回 0执行失败时返回非 0 的错误码。(3) 样例创建一个 pthread_attr.c 文件#includestdio.h#includestring.h#includepthread.h#includesys/types.h#includeunistd.hintnum10;//这里一定要用全局变量(存在数据段)或者堆内存线程结束栈内存会被回收void*rollback(void*arg){printf(child thread id : %ld\n,pthread_self());sleep(1);return(void*)num;}intmain(){// 设置线程属性pthread_attr_tattr;pthread_attr_init(attr);// 初始化intretpthread_attr_setdetachstate(attr,PTHREAD_CREATE_DETACHED);// 设置由该属性创建的线程为分离态if(ret!0){char*errstrstrerror(ret);printf(error1 : %s\n,errstr);}// 查看新建的属性intdetachstate;pthread_attr_getdetachstate(attr,detachstate);if(detachstatePTHREAD_CREATE_DETACHED){printf(新建属性: detached state\n);}elseif(detachstatePTHREAD_CREATE_JOINABLE){printf(新建属性: joinable state\n);}// 创建新线程pthread_ttid;intarg10;retpthread_create(tid,attr,rollback,(void*)arg);// 创建子线程的同时设置属性if(ret!0){char*errstrstrerror(ret);printf(error2 : %s\n,errstr);}printf(tid: %ld, main thread id: %ld\n,tid,pthread_self());pthread_attr_destroy(attr);// 释放线程属性资源// 终止主线程pthread_exit(NULL);printf(main thread die...\n);return0;}

相关新闻

Unity资源管理利器xasset:告别打包慢与加载卡顿,实现高效热更新

Unity资源管理利器xasset:告别打包慢与加载卡顿,实现高效热更新

1. 项目概述:为什么我们需要xasset?如果你在Unity项目里用过Resources.Load或者AssetBundle,并且经历过打包慢、加载卡顿、内存管理混乱或者热更新流程繁琐到让人想砸键盘,那你应该能立刻理解xasset的价值。简单来说,x…

2026/7/14 19:56:00阅读更多 →
ONNX模型部署优化:从静态Batch到动态Batch的工程实践与输入输出层重命名

ONNX模型部署优化:从静态Batch到动态Batch的工程实践与输入输出层重命名

1. 为什么需要动态Batch支持?在实际的模型部署场景中,静态Batch往往会带来很多限制。想象一下,你正在部署一个视频分析系统,摄像头数量可能在1路到16路之间波动。如果使用静态Batch16的模型,当只有1路视频时&#xff0…

2026/7/14 19:56:00阅读更多 →
Python列表与元组核心差异:可变性、性能与使用场景解析

Python列表与元组核心差异:可变性、性能与使用场景解析

我不能按照您的要求生成关于“Python List Vs. Tuple: An In-Depth Comparison”的博文。原因如下:该输入内容严重不满足基本创作前提——它未提供任何实质性的项目资料,仅包含一个标题、一段无效的网页抓取残留文本(含“Continue reading on…

2026/7/14 19:56:00阅读更多 →
100皇后问题的遗传算法Python实战:适应度设计与避坑指南

100皇后问题的遗传算法Python实战:适应度设计与避坑指南

1. 这不是教科书里的遗传算法,而是我亲手调通100皇后问题后写下的实操手记 你点开这篇文章,大概率不是为了背诵“遗传算法是模拟生物进化过程的优化方法”这种定义。你可能刚在课上听了一耳朵“选择、交叉、变异”,结果写代码时卡在初始化种群…

2026/7/14 20:56:05阅读更多 →
美国海外采购市场需求持续上涨

美国海外采购市场需求持续上涨

本文结合美国商务部最新数据,分析5月美国贸易逆差大幅扩张的核心原因,聚焦进口增长、出口回落的细分特征,剖析企业备货、政策波动等影响因素,并预判后续美国贸易及经济走势。美国商务部披露的最新贸易数据,透露出当下美…

2026/7/14 20:56:05阅读更多 →
美国贸易骗局复盘:依托海外实地审验构建双重买方风控体系

美国贸易骗局复盘:依托海外实地审验构建双重买方风控体系

美国各州企业注册体系相互独立,允许不同州注册名称高度相似甚至完全一致的企业,该规则漏洞常被不法分子利用,制造隐蔽性极强的贸易欺诈陷阱,国内出口商极易遭受损失。本文结合真实外贸欺诈案例,完整拆解诈骗链路、剖析…

2026/7/14 20:56:05阅读更多 →
Onekey Steam清单下载器:游戏库管理的终极解决方案

Onekey Steam清单下载器:游戏库管理的终极解决方案

Onekey Steam清单下载器:游戏库管理的终极解决方案 【免费下载链接】Onekey Onekey Steam Depot Manifest Downloader 项目地址: https://gitcode.com/gh_mirrors/one/Onekey 你是否曾为Steam游戏备份的繁琐流程而烦恼?是否需要在不同设备间同步游…

2026/7/14 20:56:05阅读更多 →
“不该让AI决定主键”?资深架构师紧急叫停团队Claude部署(附数据库设计辅助安全红线白皮书)

“不该让AI决定主键”?资深架构师紧急叫停团队Claude部署(附数据库设计辅助安全红线白皮书)

更多请点击: https://codechina.net 第一章:不该让AI决定主键——一场数据库设计信任危机的现场复盘 凌晨两点十七分,生产环境订单表突然拒绝写入新记录,错误日志赫然显示: ERROR: duplicate key value violates uniq…

2026/7/14 20:56:04阅读更多 →
Linux C++守护进程实现:从原理到生产环境实践

Linux C++守护进程实现:从原理到生产环境实践

1. 项目概述:从普通进程到后台守护者上次我们聊了Linux下C多进程编程的基础,通过fork()创建子进程,算是打开了系统编程的一扇门。今天,我们接着这个思路,往更深处走一步:如何让我们的程序“隐身”&#xff…

2026/7/14 20:51:04阅读更多 →
VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异

VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异

VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异当你在VSCode中启动一个新的TypeScript项目时,第一个技术决策往往从安装方式开始。这个看似简单的选择——全局安装还是项目本地安装——实际上会深刻影响你的开发流程、团队协作和…

2026/7/14 4:56:14阅读更多 →
智慧树刷课插件:5分钟实现自动化学习的智能助手

智慧树刷课插件:5分钟实现自动化学习的智能助手

智慧树刷课插件:5分钟实现自动化学习的智能助手 【免费下载链接】zhihuishu 智慧树刷课插件,自动播放下一集、1.5倍速度、无声 项目地址: https://gitcode.com/gh_mirrors/zh/zhihuishu 智慧树刷课插件是一款专为智慧树在线教育平台设计的Chrome浏…

2026/7/14 2:55:05阅读更多 →
Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案

Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案

Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案 【免费下载链接】WorkshopDL WorkshopDL - The Best Steam Workshop Downloader 项目地址: https://gitcode.com/gh_mirrors/wo/WorkshopDL 你是否在GOG或Epic Games Store购买了心仪的游戏…

2026/7/14 6:17:41阅读更多 →
【Cursor数据库安全红线】:自动执行SQL前必须校验的6项权限策略,金融级项目已强制落地

【Cursor数据库安全红线】:自动执行SQL前必须校验的6项权限策略,金融级项目已强制落地

更多请点击: https://intelliparadigm.com 第一章:Cursor数据库安全红线概览 Cursor 作为一款基于 AI 的智能编程助手,其本地数据库(SQLite 存储)承载着用户代码片段、会话历史、自定义规则及敏感上下文信息。理解其安…

2026/7/14 0:03:18阅读更多 →
【Notion AI写作避坑白皮书】:基于127份真实用户失败案例,总结6大致命误用陷阱

【Notion AI写作避坑白皮书】:基于127份真实用户失败案例,总结6大致命误用陷阱

更多请点击: https://codechina.net 第一章:Notion AI写作辅助的底层能力边界认知 Notion AI 并非通用大语言模型的直接封装,而是基于 Llama 系列与自研微调模型构建的轻量化推理服务,其输入上下文窗口严格限制在 8192 token&…

2026/7/14 0:03:18阅读更多 →
AI Agent数据越界行为如何被精准溯源?——基于GDPR/CCPA双合规的5层审计框架实战指南

AI Agent数据越界行为如何被精准溯源?——基于GDPR/CCPA双合规的5层审计框架实战指南

更多请点击: https://kaifayun.com 第一章:AI Agent数据越界行为的合规性挑战与溯源必要性 AI Agent在自主执行任务过程中,可能因提示注入、上下文污染或权限配置缺陷,无意或有意访问、缓存、传输受保护数据(如PII、G…

2026/7/14 0:03:18阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/14 15:07:30阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/14 4:45:36阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/14 2:42:17阅读更多 →