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.rhkb.cn/news/147047.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【day11.02】网络编程脑图

大小端存储&#xff1a; ip地址划分&#xff1a;

【小沐学前端】从零开始搭建一个Vue项目

文章目录 1、简介1.1 Vue 核心功能1.2 Vue API风格1.3 node环境 2、构建项目2.1 vue create2.2 vue ui2.3 vue init2.4 vite 结语 1、简介 Vue (发音为 /vjuː/&#xff0c;类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建&am…

华为云云耀云服务器L实例评测|部署在线轻量级备忘录 memos

华为云云耀云服务器L实例评测&#xff5c;部署在线轻量级备忘录 memos 一、云耀云服务器L实例介绍1.1 云服务器介绍1.2 产品优势1.3 应用场景1.4 支持镜像 二、云耀云服务器L实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置 三、部署 memos3.1 memos介绍3.2 Docker 环境搭建…

OSI体系结构和TCP/IP体系结构

在第一章&#xff08; 计网第一章 &#xff09;的时候&#xff0c;曾经提到过OSI体系结构和TCP/IP体系结构&#xff0c;并对它们进行了简单的对比。这篇博客在其基础上进行更深层次的理解。 一.OSI体系结构&#xff1a; 通信子网&#xff1a; 计算机网络在逻辑功能上可以分为…

Redis主从复制、哨兵模式、群集部署

目录 一、Redis高可用 二、Redis主从复制 主从复制的作用 主从复制的流程 实例 三、Redis哨兵模式 哨兵的核心功能 哨兵模式的作用 哨兵结构的组成 故障转移机制 实例 四、Redis群集 集群的作用&#xff0c;可以归纳为两点&#xff1a; Redis集群的数据分片&#…

wireshark of tshark tools v3.4.0版本 支持json

tshark(1) Install tshark (Wireshark) Ver.3.4.0 on CentOS7 --It must be "ps", "text", "pdml", "psml" or "fields". TCP 协议中的三次握手和四次挥手是 TCP 连接建立和关闭的过程。 三次握手 客户端向服务器发送 SYN…

Python绘图系统25:新增8种绘图函数

文章目录 常用绘图函数单选框的更改逻辑源代码 Python绘图系统&#xff1a; 前置源码&#xff1a; Python打造动态绘图系统&#x1f4c8;一 三维绘图系统 &#x1f4c8;二 多图绘制系统&#x1f4c8;三 坐 标 轴 定 制&#x1f4c8;四 定制绘图风格 &#x1f4c8;五 数据生成导…

自动混剪多段视频、合并音频、添加文案的技巧分享

在如今的社交媒体时代&#xff0c;视频的重要性越来越被人们所重视。许多人喜欢记录生活中的美好瞬间&#xff0c;并将其制作成视频分享给朋友和家人。然而&#xff0c;对于那些拍摄了大量视频的人来说&#xff0c;一个一个地进行剪辑和合并可能是一项令人头痛的任务。但是&…

GraphQL全面深度讲解

目录 一、GraphQL 是什么 二、GraphQL 规范 数据模型 字段 参数 三、运行示例 四、优势和劣势 优势 劣势 一、GraphQL 是什么 GraphQL 是一种用于 API 的查询语言&#xff0c;也是一个基于服务端的运行引擎。 GraphQL 提供了一套完整的规范和描述用于查询 API&#xf…

一种基于体素的射线检测

效果 基于体素的射线检测 一个漏检的射线检测 从起点一直递增指定步长即可得到一个稀疏的检测 bool Raycast(Vector3 from, Vector3 forword, float maxDistance){int loop 6666;Vector3 pos from;Debug.DrawLine(from, from forword * maxDistance, Color.red);while (loo…

【LeetCode热题100】--98.验证二叉搜索树

98.验证二叉搜索树 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左子树只包含 小于 当前节点的数。节点的右子树只包含 大于 当前节点的数。所有左子树和右子树自身必须也是二叉搜索树。 由于二…

【LeetCode热题100】--108.将有序数组转换为二叉搜索树

108.将有序数组转换为二叉搜索树 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 高度平衡 二叉搜索树。 高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。 二叉搜索树的中序遍历是升序…

华为云云耀云服务器L实例评测|Elasticsearch的springboot整合 Kibana进行全查询和模糊查询

前言 最近华为云云耀云服务器L实例上新&#xff0c;也搞了一台来玩&#xff0c;期间遇到各种问题&#xff0c;在解决问题的过程中学到不少和运维相关的知识。 在前几期的博客中&#xff0c;介绍了Elasticsearch的Docker版本的安装&#xff0c;Elasticsearch的可视化Kibana工具…

计算机组成与结构

目录 一、计算机硬件组成 二、中央处理单元 1、功能 2、CPU的组成 三、校验码 四、体系结构的分类 1、按处理机数量分类 2、Flynn分类 五、指令系统 1、指令 2、寻址方式 3、指令系统 #CISC&#xff08;复杂指令集计算机&#xff09; RISC&#xff08;精简指令集…

深眸科技入局AI视觉行业,以深度学习赋能视觉应用推进智造升级

随着科技的飞速发展&#xff0c;人工智能技术已经成为改变我们生活的重要力量&#xff0c;而深度学习作为人工智能的一个重要分支&#xff0c;近年来随着卷积神经网络的突破和推广&#xff0c;取得了显著进展&#xff0c;并呈现爆发式增长势头。 目前AI技术已经被迅速引入到机…

设计模式10、外观模式Facade

解释说明&#xff1a;外观模式&#xff08;Facade Pattern&#xff09;又称为门面模式&#xff0c;属于结构型模式 Faade 为子系统中的一组接口提供了一个统一的高层接口&#xff0c;该接口使得子系统更加容易使用 外观&#xff08;Facade)角色&#xff1a;为多个子系统对外提供…

【爬虫】用wget命令爬虫的简易教程

文章目录 1. 获取登录的请求2. 用postman模拟登录请求3. 用wget模拟登录请求并保存cookie4. 开始爬取网站5. 查看爬取结果6. 网站爬虫简易教程 爬取需要登录的网站的资源 背景&#xff1a;对于一些网站需要使用用户名和密码登录并且使用了https&#xff0c;我们如果不通过凭证将…

BiMPM实战文本匹配【上】

引言 今天来实现BiMPM模型进行文本匹配&#xff0c;数据集采用的是中文文本匹配数据集。内容较长&#xff0c;分为上下两部分。 数据准备 数据准备这里和之前的模型有些区别&#xff0c;主要是因为它同时有字符词表和单词词表。 from collections import defaultdict from …

Excel·VBA分列、字符串拆分

看到一篇博客《VBA&#xff0c;用VBA进行分列&#xff08;拆分列&#xff09;的2种方法》&#xff0c;使用VBA对字符串进行拆分 目录 Excel分列功能将字符串拆分为二维数组&#xff0c;Split函数举例 将字符串拆分为一维数组&#xff0c;正则表达式举例 Excel分列功能 Sub 测…

centos7卸载docker

菜鸟教程-常见命令&#xff1a;https://www.runoob.com/docker/docker-command-manual.html 1. 准备工作&#xff1a; 1.1 杀死docker有关的容器&#xff1a; docker kill $(docker ps -a -q)1.2 删除所有docker容器&#xff1a; docker rm $(docker ps -a -q)1.3 删除所有d…