深入了解Linux系统编程-(pthread)线程创建与使用
发布时间 - 2022-02-02 00:00:00 点击率:次本篇文章给大家带来了关于linux中线程的创建与使用相关知识,希望对大家有帮助。
1.前言
线程与进程的区别 (1)进程: 是操作系统调度最小单位。 Linux下可以通过ps、top等命令查看进程的详细信息。 (2)线程: 是进程调度的最小单位,每个进程都有一个主线程。在进程里主要做事情就是线程。
(3)在全系统中,进程ID是唯一标识,对于进程的管理都是通过PID来实现的。每创建一个进程,内核去中就会创建一个结构体来存储该进程的全部信息,每一个存储进程信息的节点也都保存着自己的PID。需要管理该进程时就通过这个ID来实现(比如发送信号)。当子进程结束要回收时(子进程调用exit()退出或代码执行完),需要通过wait()系统调用来进行,未回收的消亡进程会成为僵尸进程,其进程实体已经不复存在,但会虚占PID资源,因此回收是有必要的。
对于线程而言,若要主动终止需要调用pthread_exit() ,主线程需要调用pthread_join()来回收(前提是该线程没有设置 “分离属性”)。像线发送线程信号也是通过线程ID实现
进程间的通信方式: A.共享内存 B.消息队列 C.信号量 D.有名管道 E.无名管道 F.信号 G.文件 H.socket 线程间的通信方式: A.互斥量 B.自旋锁 C.条件变量 D.读写锁 E.线程信号 F.全局变量
进程间采用的通信方式要么需要切换内核上下文,要么要与外设访问(有名管道,文件)。所以速度会比较慢。而线程采用自己特有的通信方式的话,基本都在自己的进程空间内完成,不存在切换,所以通信速度会较快。也就是说,进程间与线程间分别采用的通信方式,除了种类的区别外,还有速度上的区别。
说明: 当运行多线程的进程捕获到信号时,只会阻塞主线程,其他子线程不会影响会继续执行。
2. 线程相关函数介绍
2.1 创建线程
pthread_create是Unix操作系统(Unix、Linux等)的创建线程的函数。 编译时需要指定链接库: -lpthread 函数原型
#includeint pthread_create ( pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg );
参数介绍
第一个参数为指向线程标识符的指针。 第二个参数用来设置线程属性。默认可填NULL。 第三个参数是线程运行函数的起始地址。 最后一个参数是运行函数的参数。不需要参数可填NULL。 Linux下查看函数帮助:# man pthread_create
返回值: 若线程创建成功,则返回0。若线程创建失败,则返回出错编号。 线程创建成功后, attr参数用于指定各种不同的线程属性。新创建的线程从start_rtn函数的地址开始运行,该函数只有一个万能指针参数arg,如果需要向线程工作函数传递的参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg的参数传入。
示例:
#include#include //线程函数1 void *pthread_func1(void *arg) { while(1) { printf("线程函数1正在运行.....\n"); sleep(2); } } //线程函数2 void *pthread_func2(void *arg) { while(1) { printf("线程函数2正在运行.....\n"); sleep(2); } } int main(int argc,char **argv) { pthread_t thread_id1; pthread_t thread_id2; /*1. 创建线程1*/ if(pthread_create(&thread_id1,NULL,pthread_func1,NULL)) { printf("线程1创建失败!\n"); return -1; } /*2. 创建线程2*/ if(pthread_create(&thread_id2,NULL,pthread_func2,NULL)) { printf("线程2创建失败!\n"); return -1; } /*3. 等待线程结束,释放线程的资源*/ pthread_join(thread_id1,NULL); pthread_join(thread_id2,NULL); return 0; } //gcc pthread_demo_code.c -lpthread
2.2 退出线程
线程通过调用pthread_exit函数终止执行,就如同进程在结束时调用exit函数一样。这个函数的作用是,终止调用它的线程并返回一个指向某个对象的指针。
这个函数的作用是,终止调用它的线程并返回一个指向某个对象的指针,该返回值可以通过pthread_join函数的第二个参数得到。
函数原型
#includevoid pthread_exit(void *retval);
参数解析 线程的需要返回的地址。 注意: 线程结束必须释放线程堆栈,就是说线程函数必须调用pthread_exit()结束,否则直到主进程函数退出才释放
2.3 等待线程结束
pthread_join()函数,以阻塞的方式等待thread指定的线程结束。当函数返回时,被等待线程的资源被收回。如果线程已经结束,那么该函数会立即返回。并且thread指定的线程必须是joinable(结合属性)属性。 函数原型
#includeint pthread_join(pthread_t thread, void **retval);
参数 第一个参数: 线程标识符,即线程ID,标识唯一线程。 最后一个参数: 用户定义的指针,用来存储被等待线程返回的地址。 返回值 0代表成功。 失败,返回的则是错误号。 接收线程返回值示例:
//退出线程
pthread_exit ("线程已正常退出");
//接收线程的返回值
void *pth_join_ret1;
pthread_join( thread1, &pth_join_ret1);2.4 线程分离属性
创建一个线程默认的状态是joinable(结合属性),如果一个线程结束运行但没有调用pthread_join,则它的状态类似于进程中的Zombie Process(僵死进程),即还有一部分资源没有被回收(退出状态码),所以创建线程者应该pthread_join来等待线程运行结束,并可得到线程的退出代码,回收其资源(类似于进程的wait,waitpid)。但是调用pthread_join(pthread_id)函数后,如果该线程没有运行结束,调用者会被阻塞,在有些情况下我们并不希望如此。
pthread_detach函数可以将该线程的状态设置为detached(分离状态),则该线程运行结束后会自动释放所有资源。 函数原型
#includeint pthread_detach(pthread_t thread);
参数 线程标识符 返回值 0表示成功。错误返回错误码。 EINVAL线程并不是一个可接合线程。 ESRCH没有线程ID可以被发现。
2.5 获取当前线程的标识符
pthread_self函数功能是获得线程自身的ID。 函数原型
#includepthread_t pthread_self(void);
返回值 当前线程的标识符。 pthread_t的类型为unsigned lo
ng int,所以在打印的时候要使用%lu方式,否则显示结果出问题。
2.6 自动清理线程资源
线程可以安排它退出时需要调用的函数,这样的函数称为线程清理处理程序。用于程序异常退出的时候做一些善后的资源清理。 在POSIX线程API中提供了一个pthread_cleanup_push()/pthread_cleanup_pop()函数用于自动释放资源。从pthread_cleanup_push()的调用点到pthread_cleanup_pop()之间的程序段中的终止动作(包括调用 pthread_exit()和异常终止)都将执行pthread_cleanup_push()所指定的清理函数。
注意:pthread_cleanup_push函数与pthread_cleanup_pop函数需要成对调用。 函数原型
void pthread_cleanup_push(void (*routine)(void *),void *arg); //注册清理函数 void pthread_cleanup_pop(int execute); //释放清理函数
参数 void (*routine)(void *) :处理程序的函数入口。 void *arg :传递给处理函数的形参。 int execute:执行的状态值。 0表示不调用清理函数。1表示调用清理函数。
导致清理函数调用的条件:
调用pthread_exit()函数
pthread_cleanup_pop的形参为1。 注意:return不会导致清理函数调用。
2.7 自动清理线程示例代码
#include#include #include //线程清理函数 void routine_func(void *arg) { printf("线程资源清理成功\n"); } //线程工作函数 void *start_routine(void *dev) { pthread_cleanup_push(routine_func,NULL); //终止线程 // pthread_exit(NULL); pthread_cleanup_pop(1); //1会导致清理函数被调用。0不会调用。 } int main(int argc,char *argv[]) { pthread_t thread_id; //存放线程的标识符 /*1. 创建线程*/ if(pthread_create(&thread_id,NULL,start_routine,NULL)!=0) { printf("线程创建失败!\n"); } /*2.设置线程的分离属性*/ if(pthread_detach(thread_id)!=0) { printf("分离属性设置失败!\n"); } while(1){} return 0; }
2.8 线程取消函数
pthread_cancel函数为线程取消函数,用来取消同一进程中的其他线程。
头文件: #include函数原型:pthread_cancel(pthread_t tid);
相关推荐:《Linux视频教程》
# linux
# 返回值
# 自己的
# 创建一个
# 第一个
# 可以通过
# 第二个
# 来实现
# 类似于
# 时需
# 都是
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
Laravel如何实现本地化和多语言支持_Laravel多语言配置与翻译文件管理
Laravel中间件起什么作用_Laravel Middleware请求生命周期与自定义详解
Laravel如何实现事件和监听器?(Event & Listener实战)
如何正确下载安装西数主机建站助手?
linux top下的 minerd 木马清除方法
简单实现Android文件上传
怎样使用JSON进行数据交换_它有什么限制
Laravel怎么连接多个数据库_Laravel多数据库连接配置
移动端脚本框架Hammer.js
Zeus浏览器网页版官网入口 宙斯浏览器官网在线通道
Laravel模型事件有哪些_Laravel Model Event生命周期详解
JS实现鼠标移上去显示图片或微信二维码
简历在线制作网站免费版,如何创建个人简历?
Laravel如何实现模型的全局作用域?(Global Scope示例)
今日头条微视频如何找选题 今日头条微视频找选题技巧【指南】
Laravel怎么在Blade中安全地输出原始HTML内容
HTML5建模怎么导出为FBX格式_FBX格式兼容性及导出步骤【指南】
Laravel如何自定义错误页面(404, 500)?(代码示例)
Windows家庭版如何开启组策略(gpedit.msc)?(安装方法)
Python进程池调度策略_任务分发说明【指导】
php打包exe后无法访问网络共享_共享权限设置方法【教程】
Laravel Eloquent模型如何创建_Laravel ORM基础之Model创建与使用教程
laravel服务容器和依赖注入怎么理解_laravel服务容器与依赖注入解析
制作旅游网站html,怎样注册旅游网站?
黑客如何通过漏洞一步步攻陷网站服务器?
Laravel如何实现全文搜索功能?(Scout和Algolia示例)
Microsoft Edge如何解决网页加载问题 Edge浏览器加载问题修复
厦门模型网站设计制作公司,厦门航空飞机模型掉色怎么办?
Laravel如何处理CORS跨域问题_Laravel项目CORS配置与解决方案
如何在Windows虚拟主机上快速搭建网站?
Win11怎么关闭资讯和兴趣_Windows11任务栏设置隐藏小组件
如何快速搭建FTP站点实现文件共享?
网站制作壁纸教程视频,电脑壁纸网站?
android nfc常用标签读取总结
Laravel如何使用软删除(Soft Deletes)功能_Eloquent软删除与数据恢复方法
Laravel如何获取当前登录用户信息_Laravel Auth门面使用与Session用户读取【技巧】
Python数据仓库与ETL构建实战_Airflow调度流程详解
企业网站制作这些问题要关注
公司网站制作需要多少钱,找人做公司网站需要多少钱?
java获取注册ip实例
ChatGPT 4.0官网入口地址 ChatGPT在线体验官网
Laravel怎么设置路由分组Prefix_Laravel多级路由嵌套与命名空间隔离【步骤】
制作ppt免费网站有哪些,有哪些比较好的ppt模板下载网站?
jQuery validate插件功能与用法详解
清除minerd进程的简单方法
Linux系统运维自动化项目教程_Ansible批量管理实战
如何用wdcp快速搭建高效网站?
logo在线制作免费网站在线制作好吗,DW网页制作时,如何在网页标题前加上logo?
b2c电商网站制作流程,b2c水平综合的电商平台?
弹幕视频网站制作教程下载,弹幕视频网站是什么意思?

