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

线程之多线程函数

一,线程的概念

进程是操作系统分配的最小单位,而线程是进程内部的执行单元,是操作系统CPU调度的最小单位,简单来说就是一个进程可以有多个线程。

二,与进程对比

维度进程线程
资源独立的地址空间、文件描述符等系统资源共享所属进程的地址空间和资源
调度进程是资源分配的基本单位线程是 CPU 调度的基本单位
开销创建 / 切换开销大(需复制页表等)创建 / 切换开销小(共享资源,仅保存少量寄存器)
通信需通过 IPC(管道、消息队列、共享内存)可直接读写共享变量,通信简单但需同步
健壮性进程崩溃不影响其他进程一个线程崩溃会导致整个进程退出

应用场景:

  1. 进程适用于资源隔离要求高,稳定性优先的场景,如Web服务器的工作进程,数据库的多进程架构
  2. 线程适用于高并发,计算密集型任务,如Web服务器的线程池,GUI程序的后台任务处理

三,多线程相关函数

1.前置条件

  • 头文件:
#include <pthread.h>
  • 编译时必须加链接库参数:
gcc main.c -o main -lpthread
  • 所有pthread函数成功返回0,失败返回错误码

2.创建线程:pthread_create

作用:创建一个新线程,让它开始指定的函数,参数结构如下:

int pthread_create( pthread_t *thread, // 输出:存储新线程的ID const pthread_attr_t *attr, // 线程属性(默认填NULL) void *(*start_routine)(void *), // 线程要执行的函数指针,也称入口函数 void *arg // 传递给线程函数的参数(无参数填NULL) );

3.等待线程结束:pthread_join

作用:阻塞等待指定线程执行完毕,并回收线程资源(避免内存泄漏),参数结构如下:

int pthread_join( pthread_t thread, // 要等待的线程ID void **retval // 接收线程的返回值(不接收填NULL) );

4.线程主动退出:pthread_exit

线程自己调用,主动终止运行,可以带返回值,结构如下:

void pthread_exit(void *retval); // retval:线程返回值

ps:即使主线程退出,子线程也能继续执行

5.获取线程自身线程id:pthread_self

线程获取自己的id,类似于进程的getpid,结构如下:

pthread_t pthread_self(void);

线程属性相关函数

6.分离线程:pthread_detach

将线程设置为分离态,分离态下线程退出后系统自动回收其资源,无需调用pthread_join

结构如下:

int pthread_detach(pthread_t thread);

7.初始化线程属性:pthread_attr_init

初始化线程属性对象,将属性设置为默认值,结构如下:

int pthread_attr_init(pthread_attr_t *attr);//attr需要被初始化的线程属性对象

8.设置线程属性对象的分离状态:pthread_attr_setdetachstate

用于设置线程属性对象的分离状态,结构如下:

int pthread_attr_setdetachstate( pthread_attr_t *attr, //设置分离状态的线程属性对象 int detachstate //用于指定线程的分离状态 //PTHREAD_CREATE_JOINABLE :表示将线程设置为结合态 //PTHREAD_CREATE_DETACHED :表示将线程设置为分离态 );

9.销毁线程属性:pthread_attr_destroy

销毁属性对象占用的资源,与初始化函数成对使用,结构如下:

int pthread_attr_destroy(pthread_attr_t *attr);

ps:销毁后的属性可以重新初始化,不影响已创建的线程。

线程取消相关函数

10.请求取消指定线程:pthread_cancel

向指定线程发送取消请求,它只是一个请求,调用成功也只是代表请求已提交,不代表线程已经终止了,结构如下:

int pthread_cancel(pthread_t thread);

11.设置取消状态:pthread_setcancelstate

设置调用线程自身的取消状态,即是否允许响应pthread_cancel的请求,参数:

参数说明
state

新的取消状态,二选一:

PTHREAD_CANCEL_ENABLE(默认):允许响应取消请求

PTHREAD_CANCEL_DISABLE:禁止响应取消请求(请求会被暂时挂起)

oldstate输出参数,存储修改前的旧状态(传NULL表示不需要保存旧状态)
int pthread_setcancelstate(int state, int *oldstate);

12.设置取消类型:pthread_setcanceltype

设置调用线程自身的取消类型,仅在取消状态为PTHREAD_CANCEL_ENABLE时生效,决定线程收到请求后何时终止,参数:

参数说明
type

新的取消类型,二选一:

PTHREAD_CANCEL_DEFERRED(默认,延时取消):线程不会立刻终止,直到下一个取消点(Cancellation Point)才响应

PTHREAD_CANCEL_ASYNCHRONOUS(异步取消):线程收到请求后会 “随时终止”,风险极高

oldtype输出参数,存储修改前的旧类型(传NULL表示不需要保存旧类型)
int pthread_setcanceltype(int type, int *oldtype);

13.取消函数的示例代码

//请求取消指定线程 /* 请求取消指定线程取决于线程的取消状态和取消类型 取消状态:可取消和不可取消 取消类型:延时取消和可被立即取消(异步取消) 三种情况: 1. 可取消的线程+延时取消 2. 可取消的线程+可被立即取消 3. 不可取消的线程 */ #include <stdio.h> #include <pthread.h> #include <string.h> #include <unistd.h> #include <stdlib.h> //情况1:可取消的线程+延时取消 void *thread1(void *arg) { //设置线程1取消状态和取消类型 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL); pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL); while(1) { //结果:不会每隔1秒打印一次线程1正在运行... //因为线程1收到请求取消信号,线程1会在取消点进行取消 printf("线程1正在运行...\n"); sleep(1); } return NULL;//注意:此处返回值不可以为丢,没有实际意义 } //情况2:可取消的线程+可被立即取消 void *thread2(void *arg) { //设置线程2取消状态和取消类型 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL); while(1) { //因为设置为了立即取消,所以线程2会立即取消 //所以将sleep注释之后无法显示 printf("线程2正在运行...\n"); //sleep(1); } return NULL;//注意:此处返回值不可以为丢,没有实际意义 } //情况3:不可取消的线程 void *thread3(void *arg) { //设置线程3取消状态为不可取消 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL); while(1) { //因为设置为了不可取消,所以线程3不会取消 printf("线程3正在运行...\n"); sleep(1); } return NULL;//注意:此处返回值不可以为丢,没有实际意义 } int main(int argc,const char *argv[]) { //情况1:可取消的线程+延时取消 pthread_t tid1 = 0; int ret = pthread_create(&tid1,NULL,thread1,NULL); if(ret != 0) { fprintf(stderr,"创建线程1失败,错误信息:%s\n",strerror(ret)); return -1; } printf("创建线程1成功,线程1ID:%ld\n",tid1); //情况2:可取消的线程+可被立即取消 pthread_t tid2 = 0; int ret2 = pthread_create(&tid2,NULL,thread2,NULL); if(ret2 != 0) { fprintf(stderr,"创建线程2失败,错误信息:%s\n",strerror(ret2)); return -1; } printf("创建线程2成功,线程2ID:%ld\n",tid2); //情况3:不可取消的线程 pthread_t tid3 = 0; int ret3 = pthread_create(&tid3,NULL,thread3,NULL); if(ret3 != 0) { fprintf(stderr,"创建线程3失败,错误信息:%s\n",strerror(ret3)); return -1; } printf("创建线程3成功,线程3ID:%ld\n",tid3); //请求取消指定的线程1 int ret_cancel = pthread_cancel(tid1); //只能说明请求取消成功,不能说明会被立即取消 if(ret_cancel != 0) { fprintf(stderr,"请求取消线程1失败,错误信息:%s\n",strerror(ret_cancel)); return -1; } printf("请求取消线程1成功\n"); //请求取消指定的线程2 int ret_cancel2 = pthread_cancel(tid2); if(ret_cancel2 != 0) { fprintf(stderr,"请求取消线程2失败,错误信息:%s\n",strerror(ret_cancel2)); return -1; } printf("请求取消线程2成功\n"); //请求取消指定的线程3 int ret_cancel3 = pthread_cancel(tid3); if(ret_cancel3 != 0) { fprintf(stderr,"请求取消线程3失败,错误信息:%s\n",strerror(ret_cancel3)); return -1; } printf("请求取消线程3成功\n"); //阻塞等待线程退出 pthread_join(tid1,NULL); pthread_join(tid2,NULL); pthread_join(tid3,NULL); return 0; }
http://www.jsqmd.com/news/856712/

相关文章:

  • 嵌入式异构多处理器评估板:从核心原理到工业应用实战
  • 分享高效牧草种子生产厂,适合青贮制作的优质厂家 - myqiye
  • logitech-pubg项目完整指南:罗技鼠标宏绝地求生压枪终极方案
  • 拆解OpenTSN 3.2:如何用一套硬件逻辑,灵活拼出交换机与网卡?
  • 解锁伯远生物表观遗传学:细胞记忆与命运的抉择
  • 告别踩坑!RocketMQ Dashboard最新版(Spring Boot)打包、配置与启动避坑指南
  • 分享有机溶剂脱水推荐厂家选购指南,九天高科是优质之选 - myqiye
  • UE5.1升级后MetaHuman动不了?手把手教你修复增强输入系统适配问题
  • 掌握AMD Ryzen硬件调试:SMUDebugTool从入门到精通的完整指南
  • ViGEmBus虚拟游戏控制器驱动:5分钟快速上手指南,让你的游戏体验升级!
  • 2026年4月做得好的特种光纤中心推荐,特种光纤/量子科技/探测器,特种光纤厂家选哪家 - 品牌推荐师
  • 销售易NeoAgent 2.0深度解析:从“业务语义本体“到“智能体矩阵“的技术架构
  • Shell脚本应用(一)---Shell脚本入门(基础+理论+实操+实例)-004篇
  • 别再只盯着Mesh了!聊聊NoC拓扑那些被低估的‘冷门’选手:Crossbar、蝶形与Clos网络
  • 不止是UART:深入瑞萨RA_FSP的SCI模块,解锁SPI、I2C和智能卡接口的复用秘籍
  • 性价比高的三维动画设计公司推荐,如何选? - mypinpai
  • ComfyUI Manager插件架构优化:5种高效部署方案与性能调优指南
  • AD导出Gerber文件时,单位选英寸格式选2:5?一文讲透这些‘祖传’设置背后的原因
  • Java中List之间求交集
  • EI会议投稿踩坑记:手把手教你搞定PDF Express字体嵌入和合规邮件(附免费工具)
  • 专业的济南育婴师服务公司
  • 告别环境配置烦恼:用Docker一键部署博流BL616/BL808 RISC-V SDK编译环境(支持Win/Mac/Linux)
  • 5分钟快速清理Windows右键菜单:ContextMenuManager终极优化指南
  • CentOS 7.9扩容实战:手把手教你给VMware虚拟机加一块40G硬盘(附永久挂载配置)
  • 复合套装门选购指南:靠谱生产商与性价比之选 - mypinpai
  • XXMI启动器:6款热门二次元游戏模组一站式管理终极指南
  • Markdown图文教程转Word、PDF文档
  • Windows右键菜单终极清理教程:ContextMenuManager免费工具帮你告别臃肿与卡顿
  • Spring Boot 3 + Security 6实战:从零搭建一个带JWT和Redis的登录认证系统(附完整源码)
  • 王铎这幅字挂出来,90%的人连第一笔的调锋都没看懂