Linux系统编程系列之线程

一、什么是线程

        线程(Thread)是计算机中的基本执行单元,是操作系统调度的最小单位。线程是进程内的一个独立执行流程,一个进程可以包含多个线程,这些线程共享进程的资源,但每个线程都有自己的独立栈空间以及程序计数器。

二、线程与进程的优缺点

        1、线程的优点

        (1)、线程创建和销毁的开销比进程小,因为线程共享进程中的地址空间和其他资源。

        (2)、线程可以同时执行多个任务,提高了系统的并发性能。

        (3)、线程之间的通信和同步比进程之间的通信和同步更快捷和简单,因为线程共享同一进程的内存。

        (4)、线程可用于执行GUI等交互性任务而不会卡住整个应用程序。

        2、线程的缺点

        (1)、 多线程访问共享数据时,需要使用同步技术,否则会导致不可预期的结果。

        (2)、 线程的调试和bug定位比较困难,因为多个线程共享进程的执行环境。

        (3)、 如果线程中出现了异常,可能会影响整个进程。

        3、进程的优点

        (1)、 进程相互独立,不会相互影响,因此更加健壮和安全。

        (2)、进程可以在不同的硬件和操作系统上运行,更具有可移植性。

        (3)、 进程使用管道等IPC(进程间通信)机制可以方便的实现进程之间的通信和同步。

        4、进程的缺点

        (1)、进程创建和销毁的开销比较大,因为每个进程都需要独立的地址空间和系统资源。

        (2)、进程之间通信和同步需要使用IPC技术,比较繁琐和复杂。

        (3)、进程的并发性能比较差,不能同时执行多个任务。

三、线程的使用场景

        1、多任务处理:多线程可以同时处理多个任务,提高程序的执行效率和响应速度。

        2、并发访问:当多个线程同时访问共享资源时,需要使用线程控制技术,避免出现竞态条件和死锁等问题。

        3、异步编程:线程可以在后台执行一些耗时的操作,不会阻塞主线程,提高程序的用户体验。

        4、服务器编程:服务器一般要同时处理多个客户端请求,使用多线程可以提高服务器的并发处理能力。

        5、图形界面编程:图形界面程序中需要使用线程避免阻塞用户界面,实现异步更新UI界面。

        6、大数据处理:对于大数据处理和分析,多线程可以提高数据处理的效率和速度。

        7、游戏开发:游戏开发中需要实时更新游戏画面和处理用户输入,需要使用多线程技术实现。

四、与线程有关的函数API

        1、线程的创建

        创建一条POSIX线程非常简单,只需要指定线程的执行函数即可

// 创建一条线程
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);// 接口说明:返回值:成功返回0,失败返回一个错误码参数thread:新线程的TID参数attr:线程属性,若创建标准线程则该参数可设置为NULL参数start_routine:线程函数,是一个回调函数,跟信号的例程函数有点像参数arg:线程函数的参数

         2、线程的退出

        与进程类似,当一条线程执行完毕其任务时,可以使用接口来退出

// 线程的退出
void pthread_exit(void *retval);// 接口说明参数retval:线程的返回值,若线程没有数据可返回则可写成NULLpthread_exit()与exit()的区别
pthread_exit():退出当前线程
exit():退出当前进程(即退出进程中的所有进程)

         3、线程的结合

        与进程类似,线程退出后不会立即释放其所占有的系统资源,而会成为一个僵尸线程。其他线程可使用pthread_join()来释放僵尸线程的资源,并可获得其退出时返回的退出值,该函数接口被称为线程的接合函数:

// 阻塞等待指定线程退出
int pthread_join(pthread_t tid, void **val);// 非阻塞接合指定线程退出
int pthread_tryjoin_np(pthread_t tid, void **retval);// 在指定时间内阻塞接合指定线程的退出
int pthread_timedjoin_np(pthread_t tid, void **retval, const struct timespec *ashtime);// 接口说明(1)若指定tid的线程尚未退出,那么该函数将持续阻塞(2)若只想阻塞等待指定线程tid退出,而不想要其退出值,那么val可置为NULL(3)若指定tid的线程处于分离状态,或者不存在,则该函数会出错返回

        4、获取线程TID

        

// 获取线程TID
pthread_t pthread_self(void);// 接口说明返回值:线程TID该接口类似进程管理中的getpid(),但是进程的PID是系统全局资源,而线程的TID仅限于进程内部的线程间有效。当我们要对某条线程执行发送信号,取消,阻塞接合等操作时,需要用到线程的TID。

        5、线程错误码

        线程函数对系统错误码的处理跟标准C库函数的处理方式有很大不同,标准C库函数会对全局错误码errno进行设置,而线程函数发生错误时会直接返回错误码。以线程接合为例,若要判定接合是否成功,成功的情况下输出僵尸线程的退出值,失败的情况下输出失败的原因,实现代码应该这么写

#include <error.h> // 头文件中定义了errno变量void *val;errno = pthread_join(tid, &val);if(errno == 0)
{printf("成功接合线程,其退出值为:%d\n", (int)val;
}
else
{perror("接合线程失败");
}

        6、函数单例

        许多时候,我们希望某个函数只被严格执行一次,这种需求在一些初始化功能模块中尤为常见,但是如果某个进程中内含多条线程,无法预先知晓哪条线程会先执行,那么初始化就会被执行多次,但如果使用函数单例就会只执行一次。

// 函数单例启动接口
int pthread_once(pthread_once_t *once_control, void (*init_routine)(void));// 接口说明参数once_control:用来关联某个函数单例,被关联的函数单例只会被执行一遍参数init_routine:函数指针指向的函数就是只执行一遍的函数单例// 通常参数once_control指定为函数单例控制pthread_once_t once_control = PTHREAD_ONCE_INIT;

五、案例

// 线程的案例#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>int flag = 0;   // 简单的标志位来控制同步
char data[100];// 线程1的例程函数,用来接收数据
void *recv_routine(void *arg)
{printf("I am recv_routine, my tid = %ld\n", pthread_self());while(1){if(flag){printf("pthread1 read data: %s\n", data);memset(data, 0, sizeof(data));flag = 0;}}
}// 线程2的例程函数,用来发送数据
void *send_routine(void *arg)
{printf("I am send_routine, my tid = %ld\n", pthread_self());while(1){printf("please input data:\n");fgets(data, 100, stdin);printf("pthread2 send data\n");flag = 1;}
}int main(int argc, char *argv[])
{pthread_t tid1, tid2;// 创建线程1,用来接收数据errno = pthread_create(&tid1, NULL, recv_routine, NULL);if(errno == 0){printf("pthread create recv_routine success, tid = %ld\n", tid1);}else{perror("pthread create recv_routine fail\n");}// 创建线程2,用来发送数据errno = pthread_create(&tid2, NULL, send_routine, NULL);if(errno == 0){printf("pthread create send_routine success, tid = %ld\n", tid2);}else{perror("pthread create send_routine fail\n");}// 一定要加这个,否则主函数直接退出,相当于进程退出,所有线程也退出// 或者加上while(1)等让主函数不退出pthread_exit(0);return 0;
}

六、总结

        线程可以提供系统的并发性,开销比进程更加小,但是不如进程健壮,移植性好。线程有自己的属性,下一篇博客将讲解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/147510.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

挺进欧洲:中国汽车如何破解品牌与成本双重困境?

摘要&#xff1a;2022年&#xff0c;中国超越德国&#xff0c;跻身全球第二大汽车出口大国&#xff0c;仅次于日本。历经国内市场的激烈竞争和技术积累,中国汽车品牌凭借在新能源技术上的优势和制造力,决定挑战欧洲-BBA(奔驰、宝马、奥迪)的主场。令人惊讶的是,尽管在21世纪初,…

PCB放置过孔技巧

合理的放置过孔能有效的节约面积。 我们根据嘉立创的pcb工艺能力中写出单双面板最小过孔为0.3mm(内径)/0.5mm(外径) 设置过孔尺寸外直径为24mil&#xff08;0.61mm&#xff09;&#xff09;内直径为12mil&#xff08;0.305mm&#xff09; 嘉立创PCB工艺加工能力范围说明-嘉立…

扩容LVM卷导致lvm元数据丢失的恢复过程

一、问题描述 因某次MySQL binlog占用过高扩容时&#xff0c;是直接对云盘操作&#xff0c;而扩容直接操作了lvm卷而未操作云盘分区&#xff0c;并随后执行了扩容的partprobe&#xff0c;resize2fs卷等操作&#xff1b;最后&#xff0c;显示并未扩容成功&#xff0c;重启系统后…

基于YOLOv8的安全帽检测系统(2):Gold-YOLO,遥遥领先,助力行为检测 | 华为诺亚NeurIPS23

目录 1.Yolov8介绍 2.安全帽数据集介绍 3.Gold-YOLO 4.训练结果分析 1.Yolov8介绍 Ultralytics YOLOv8是Ultralytics公司开发的YOLO目标检测和图像分割模型的最新版本。YOLOv8是一种尖端的、最先进的&#xff08;SOTA&#xff09;模型&#xff0c;它建立在先前YOLO成功基础上…

centos 部署nginx 并配置https

centos版本&#xff1a;centos 7.8 &#xff08;最好不要用8&#xff0c;8的很多用法和7相差很大&#xff09; 一.安装nginx 1。下载Nginx安装包&#xff1a;首先&#xff0c;访问Nginx的官方网站&#xff08;https://nginx.org/&#xff09;或您选择的镜像站点&#xff0c;找…

【2023年11月第四版教材】第17章《干系人管理》(第二部分)

第17章《干系人管理》&#xff08;第二部分&#xff09; 4 过程1-识别干系人4.1 数据收集★★★4.3数据分析4.4 权力利益方格4.5 数据表现&#xff1a;干系人映射分析和表现★★★ 5 过程2-规划干系人参与5.1 数据分析5.2 数据表现★★★5.2.1 干系人参与度评估矩阵★★★ 5.3 …

原型、原型链、判断数据类型

目录 作用 原型链 引用类型&#xff1a;__proto__(隐式原型)属性&#xff0c;属性值是对象函数&#xff1a;prototype(原型)属性&#xff0c;属性值是对象 Function&#xff1a;本身也是函数 相关方法 person.prototype.isPrototypeOf(stu) Object.getPrototypeOf(objec…

【LeetCode热题100】--102.二叉树的层序遍历

102.二叉树的层序遍历 广度优先搜索&#xff1a; 我们可以想到最朴素的方法是用一个二元组 (node, level) 来表示状态&#xff0c;它表示某个节点和它所在的层数&#xff0c;每个新进队列的节点的 level 值都是父亲节点的 level 值加一。最后根据每个点的 level 对点进行分类&…

c#设计模式-结构型模式 之 装饰者模式

&#x1f680;介绍 在装饰者模式中&#xff0c;装饰者类通常对原始类的功能进行增强或减弱。这种模式是在不必改变原始类的情况下&#xff0c;动态地扩展一个对象的功能。这种类型的设计模式属于结构型模式&#xff0c;因为这种模式涉及到两个类型之间的关系&#xff0c;这两个…

Ubuntu 20.04编译GPMP2过程记录

前言 GPMP2是董靖博士等人在16-17年提出的结合GTSAM因子图框架与Gaussian Processes完成motion planning的一项工作。前身源于Barfoot教授的课题组提出的STEAM(Simultaneous Trajectory Estimation and Mapping)问题及其相关工作。在提出董靖博士提出GPMP2后&#xff0c;borgl…

时序分解 | Matlab实现SSA-VMD麻雀算法优化变分模态分解时间序列信号分解

时序分解 | Matlab实现SSA-VMD麻雀算法优化变分模态分解时间序列信号分解 目录 时序分解 | Matlab实现SSA-VMD麻雀算法优化变分模态分解时间序列信号分解效果一览基本介绍程序设计参考资料 效果一览 基本介绍 SSA-VMD麻雀搜索算法SSA优化VMD变分模态分解 可直接运行 分解效果好…

论文笔记:TMN: Trajectory Matching Networks for PredictingSimilarity

2022 ICDE 1 intro 1.1 背景 轨迹相似度可以划分为&#xff1a; 非学习度量方法 通常是为一两个特定的轨迹距离度量设计的&#xff0c;因此不能与其他度量一起使用通常需要二次时间&#xff08;O(n^2)&#xff09;来计算轨迹之间的精确距离基于学习的度量方法 利用机器学习…

源码编译tcpreplay,及使用方法

编译步骤: 下载源码 解压 ./configure make sudo make install 使用方法: tcpreplay --loop1 --intf1网卡名 -x1 pcap文件名 实测结果: 左边是输入的tcpreplay命令 右边是tcpdump截获的udp包

[MAUI程序设计] 用Handler实现自定义跨平台控件

今天来谈一谈MAUI跨平台技术的核心概念——跨平台控件。 无论是MAUI,Xamarin.Forms还是其它的跨平台技术,他们是多个不同平台功能的抽象层,利用通用的方法实现所谓“一次开发,处处运行”。 跨平台框架需要考虑通用方法在各平台的兼容,但由于各原生平台(官方将原生称为本…

ffmpeg、ffplay在线安装,离线导出整个程序,移植到其他服务器使用(linux系统)

环境说明 以ubuntu系统作为说明 在线安装 下面命令会同时安装ffplay和ffmpeg sudo apt-get install ffmpeg怎么验证安装成功&#xff1f; 输入ffmpeg命令 ffmpeg&#xff0c;如图则说明安装成功 转储可执行程序和依赖的文件 找到安装路径&#xff0c;一般在/usr/bin目录…

C++标准模板(STL)- 类型支持 (std::size_t,std::ptrdiff_t,std::nullptr_t)

对象、引用、函数&#xff08;包括函数模板特化&#xff09;和表达式具有称为类型的性质&#xff0c;它限制了对这些实体所容许的操作&#xff0c;并给原本寻常的位序列提供了语义含义。 附加性基本类型及宏 sizeof 运算符返回的无符号整数类型 std::size_t 定义于头文件 <…

电脑显示系统错误怎么办?

有时我们在开机时会发现电脑无法开机&#xff0c;并显示系统错误&#xff0c;那么这该怎么办呢&#xff1f;下面我们就一起来了解一下。 方法1. 替换SAM文件解决问题 1. 重启电脑并进入安全模式。 Win8/10系统&#xff1a;在启动电脑看到Windows标志时&#xff0c;长按电源键…

机器人中的数值优化(二十)——函数的光滑化技巧

本系列文章主要是我在学习《数值优化》过程中的一些笔记和相关思考&#xff0c;主要的学习资料是深蓝学院的课程《机器人中的数值优化》和高立编著的《数值最优化方法》等&#xff0c;本系列文章篇数较多&#xff0c;不定期更新&#xff0c;上半部分介绍无约束优化&#xff0c;…

大数据Flink(九十五):DML:Window TopN

文章目录 DML:Window TopN DML:Window TopN Window TopN 定义(支持 Streaming):Window TopN 是一种特殊的 TopN,它的返回结果是每一个窗口内的 N 个最小值或者最大值。 应用场景

zemax场曲/畸变图与网格畸变图

网格畸变是XY两个方向上的几何畸变&#xff0c;是不同视场实际像高与近轴像高的偏差。 垂轴放大率在整个视场范围内不能保持常数 当一个有畸变的光学系统对一个方形的网状物体成像时,若δy>0&#xff0c;则主光线的交点高度y比理想像高y低,视场越大&#xff0c;低得越多&a…