线程与多线程(一)
线程与多线程(一)
- 一、线程
- 1、概念
- 2、示意图
- 3、虚拟地址转换到物理地址
- 4、与进程相比的优点
- 5、与进程相比的缺点
- 6、与进程的关系
- (1)线程独有
- (2)共享
- (3)示意图
- 二、POSIX线程库
- 三、创建线程
- 1、函数
- 2、概念
- 四、pthread_self
- 1、函数
- 2、概念
- 3、pthread_t
- 4、示意图
- 5、说明
- 五、线程终止
- 1、方式
- 2、pthread_exit
- (1)函数
- (2)概念
- 3、pthread_cancel
- (1)函数
- (2)概念
- 六、线程等待
- 1、函数
- 2、概念
- 3、意义
- 七、线程库
- 八、示例代码
- 1、代码
- 2、运行结果
- 九、分离线程
- 1、函数
- 2、概念
- 3、代码
- 4、运行结果
一、线程
1、概念
- 线程也被称为轻量级进程(Lightweight Process,LWP),它是程序执行流的最小单元、操作系统调度的基本单位。用户级执行流与内核LWP间是一一对应的。
- 在整个生命周期中,相比于进程,线程的创建和释放更加轻量化;进程内线程的切换不需要重新cache数据,进程内线程的切换(运行)更加轻量化。
- 在Linux中没有真正义上的线程,所谓的线程是用进程(内核数据结构)模拟的线程。
- 一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。但由于线程之间的相互制约,线程在运行中呈现出间断性。
- 在进程的虚拟地址空间中,进程拥有大部分资源。将进程的这些资源合理分配给每个执行流就形成了线程执行流。即进程是承担分配系统资源(本质为地址空间范围)的基本实体,线程是进程内部的执行流资源。所以,线程是进程内的一个执行分支,它执行一部分进程的代码,执行粒度要比进程细。
- 每一个程序都至少拥有一个线程,即程序本身。而线程是程序中一个单一的顺序控制流程。所以,多线程是在单个程序(进程)中同时运行多个线程完成不同的工作。
2、示意图
3、虚拟地址转换到物理地址
4、与进程相比的优点
- 创建一个新线程的代价较小。
- 线程之间的切换需要操作系统做的工作较少。
- 占用的资源较少,能充分利用多处理器的可并行数量。
- 在等待慢速I/O操作结束的同时,程序可执行其他计算任务。
- 在I/O密集型应用中,可将I/O操作重叠来提高性能。这样线程就可以同时等待不同的I/O操作。
- 计算密集型应用时,可将计算分解到多个线程中以实现在多处理器系统上运行的目的。
- 合理的使用多线程,能提高CPU密集型程序的执行效率、IO密集型程序的用户体验。
5、与进程相比的缺点
- 性能损失:一个很少被外部事件阻塞的计算密集型线程往往无法与其它线程共享同一个处理器。
- 健壮性降低:在一个多线程程序里,因为时间分配上的细微偏差或者因为共享了不该共享的变量而造成不良影响的可能性较大。
- 缺乏访问控制:因为进程是访问控制的基本粒度。所以,在一个线程中调用某些系统函数会对整个进程造成影响。
- 编程难度高:编写与调试一个多线程程序比单线程程序困难。
- 影响较大:因为线程是进程的执行分支。所以,线程出现异常就类似于进程出现异常。当触发信号机制终止时,整个进程都将终止,该进程内的所有线程也将退出。即如果一个线程崩溃了,这个线程所在的进程内的所有线程都将出错崩溃。
6、与进程的关系
(1)线程独有
- 线程ID、一组寄存器、栈空间、errno、信号屏蔽字、调度优先级。
(2)共享
- 文件描述符表、每种信号的处理方式(SIG_ IGN、SIG_ DFL或者自定义的信号处理函数)、当前工作目录、用户id和组id。
(3)示意图
二、POSIX线程库
- 与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以 pthread_ 开头。
- 当使用POSIX线程库的函数时,需要引用头文件pthread.h。
- 当链接POSIX线程库时,需要使用编译器命令的 -lpthread 选项。
三、创建线程
1、函数
2、概念
- pthread_create函数在调用进程中启动一个新线程,该新线程通过调用参数start_routine所指向的函数开始执行,参数arg作为start_routine指向的函数的唯一传递的参数。
- 参数attr指向一个pthread_attr_t结构体,其内容在线程创建时用于确定新线程的属性。该结构使用pthreadattr_init和相关函数进行初始化。如果attr为NULL,则使用默认属性创建线程。
- 在返回之前,如果成功调用了pthread_create函数,该函数会将新线程的ID存储在线程指向的缓冲区中。此标识符(参数thread,即线程ID)用于在后续调用其他pthread函数时引用对应的线程。
- 新线程继承了调用创建线程函数的线程的信号掩码(pthread_sigmask)的副本,浮点环境(fenv)。但不继承其备用信号堆栈(sigaltstack)。
- 新线程挂起信号集(sigpending)为空,CPU时间时钟的初始值为0。
四、pthread_self
1、函数
2、概念
- pthread_self()函数返回调用此函数的线程的线程ID。这与创建此线程的线程在调用pthread_create函数成功后,参数thread返回的值相同。
3、pthread_t
- 在Linux目前实现的NPTL实现来说,pthread_t类型的线程ID本质是一个进程地址空间上的一个地址。
4、示意图
5、说明
- 在上方的示意图中,struct pthread、线程局部存储和线程栈的一整块是线程的tcb,即线程控制块。而每一个线程的库级别的tcb的起始地址是线程的tid,类型为pthread_t。
- 在进程中,除了主线程以外的其他所有线程的独立栈都在共享区中。具体是在pthread库中,tid指向的用户tcb中。
- 每一个线程都有自己独立的栈结构,线程栈上的数据可以被同一进程内的其他线程看到并访问。
- 如果线程想要一个私有的全局变量,可以在全局变量的定义前面加__thread编译选项。这是线程的局部存储,只能定义内置类型而不能用来修饰自定义类型。
五、线程终止
1、方式
- 调用pthread_exit函数,指定一个退出状态值,该值可供调用pthread_join函数的同一进程中的另一个线程使用。
- 从start_routine指向的函数返回。这相当于使用return语句中提供的值调用pthread_exit函数。
- 被pthread_cancel函数取消。
- 进程中的任何线程调用exit函数,或者主线程执行main函数的返回。都会导致进程中所有线程的终止。
2、pthread_exit
(1)函数
(2)概念
- pthread_exit函数终止调用该函数的线程,并通过retval返回一个值,该值(如果线程是joinable的)可供调用pthread_join的同一进程中的另一个线程使用。
- 当线程终止时,进程共享资源(例如互斥锁、条件变量、信号量和文件描述符)不会被释放。
- 在进程中的最后一个线程终止后,该进程通过调用退出状态为零的exit来终止,进程共享资源将被释放。
- pthread_exit函数或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的,不能在将退出的线程所执行的函数的栈上分配。因为当其它线程得到这个返回指针时,该线程已经退出了。此时访问该内存单元的结果是未知的。
3、pthread_cancel
(1)函数
(2)概念
- pthread_cancel函数向thread线程发送取消请求。目标线程是否以及何时对取消请求做出反应取决于该线程控制的两个属性,即其可取消性状态和类型。
- 被取消的线程终止后,调用pthread_join等待该线程的线程将获得 PTHREAD_CANCELED 作为该线程的退出状态。Joining(等待)一个线程是知道取消操作是否已完成的唯一方法。
- 一个线程可以调用pthread_ cancel函数终止同一进程中的另一个线程。
六、线程等待
1、函数
2、概念
- pthread_join函数等待thread指定的线程终止。如果该线程已经终止,则pthread_join函数立即返回,否则阻塞等待。thread指定的线程必须是joinable(可等待)的。
- 如果retval不为NULL,则pthread_join函数将目标线程的退出状态,即目标线程提供给pthread_exit的值或者执行函数结束时返回的值,复制到retval指向的位置。如果目标线程被取消,则 PTHREAD_CANCELED 将被放置在retval中。
- 如果多个线程同时尝试等待同一个线程,则结果是未定义的。如果调用pthread_join函数的线程被取消,那么目标线程将保持joinable状态。即它不会被detached(分离)。
3、意义
- 如果不进行等待,则已经退出的线程的空间不会被释放,仍然在进程的地址空间内,有可能造成内存泄漏。
- 如果不进行等待,创建新的线程不会复用退出线程的地址空间,而当申请线程的数量达到一定值时,有可能会内存不足。
七、线程库
- 内核中没有很明确得线程概念,只有轻量级进程的概念。所以,Linux操作系统不会直接提供线程相关的系统调用,只会提供轻量级进程的系统调用。
- pthread线程库是在应用层对轻量级进程接口进行封装,为用户提供直接线程的接口。
- 几乎所有的Linux平台都默认自带pthread线程库。当在Linux中编写多线程代码时,需要使用第三方的pthread库。
- 因为线程库需要维护线程的概念而不用维护线程的执行流。所以,库需要对线程进行管理,使用时需要加载到内存中,即原生线程库是基于内存的。
八、示例代码
1、代码
string ToHex(pthread_t tid)
{char buff[64];snprintf(buff, sizeof(buff), "%p", tid);return buff;
}void *RunRoutine(void *arg)
{char *threadName = (char*)arg;for(int i = 0; i < 5; ++i){cout << threadName << ", tid: " << ToHex(pthread_self()) << ", is running " << i << endl;sleep(1);//pthread_exit((void*)1);if(i == 2){//exit(1);//return (void*)1;}}}int main()
{pthread_t tid;pthread_create(&tid, nullptr, RunRoutine, (void*)"thread 1");cout << "main thread create work done, new thread id: " << ToHex(tid) << endl;// sleep(1);// pthread_cancel(tid);// cout << "main thread: " << getpid() << " , thread tid " << ToHex(tid) << " canceled" << endl;// sleep(1);int ret = pthread_join(tid, nullptr);cout << "pthread_join wait over, ret = " << ret << endl;return 0;
}
2、运行结果
- 放开pthread_exit行注释。
- 放开exit行注释。
- 放开return行注释。
- 放开main内注释。
九、分离线程
1、函数
2、概念
- pthread_detach函数可将thread标识的线程标记为已分离,但尝试分离已分离的线程的行为是未定义的。
- 当一个分离的线程终止时,它的资源会自动释放回系统,而不需要另一个线程去等待它。
- 可以是线程组内其他线程对目标线程进行分离,也可以是线程自己分离。
- joinable和分离是冲突的,即一个线程不能既是joinable又是分离的。
3、代码
void *RunRoutine(void *arg)
{pthread_detach(pthread_self());char *threadName = (char*)arg;for(int i = 0; i < 5; ++i){cout << threadName << ", tid: " << pthread_self() << ", is running " << i << endl;sleep(1);}}int main()
{pthread_t tid;pthread_create(&tid, nullptr, RunRoutine, (void*)"thread 1");cout << "main thread create work done, new thread id: " << tid << endl;sleep(6);cout << "sleep time over" << endl;return 0;
}
4、运行结果
本文为线程相关的内容,多线程相关的内容参见线程与多线程(二)。
本文到这里就结束了,如有错误或者不清楚的地方欢迎评论或者私信
创作不易,如果觉得博主写得不错,请点赞、收藏加关注支持一下💕💕💕
相关文章:

线程与多线程(一)
线程与多线程(一) 一、线程1、概念2、示意图3、虚拟地址转换到物理地址4、与进程相比的优点5、与进程相比的缺点6、与进程的关系(1)线程独有(2)共享(3)示意图 二、POSIX线程库三、创…...

连接其他主机上的redis连接不上`telnet: Unable to connect to remote host: Connection refused`
telnet: Unable to connect to remote host: Connection refused 这个错误通常表示目标主机(192.168.8.29)上的服务(6379端口)没有运行,或者主机的防火墙/网络设置阻止了连接。 你可以尝试以下步骤来解决问题…...
dijkstral算法详解
import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Map;public class test39 {// 定义节点类,表示图中的顶点public static class Node {public int value; // 节点的值,即编号public int in; // 进入…...

创意指南丨AR数学沉浸式空间体验
AR学习种类那么多,哪款最吸引你? 星河造梦坊和Unity联手打造的沉浸式空间AR无疑是其中的佼佼者。 这款应用不仅利用AR技术将抽象的数学概念变得生动有趣,还通过互动体验让学习者仿佛置身于一个充满奇幻色彩的数学世界中。 无论是学生还是教…...

linux文件——深度学习文件fd、文件系统调用
前言:从本片开始正式进入linux文件的学习,本片内容主要是文件的fd。 本篇内容博主将要先带友友回忆C语言中的文件操作接口,然后再过渡到操作系统中的系统调用的学习,最后理解操作系统中的文件操作。 ps:本节内容设计一…...

003集——C#数据类型 及大小端序转换——C#学习笔记
如需得到一个类型或一个变量在特定平台上的准确尺寸,可以使用 sizeof 方法。表达式 sizeof(type) 产生以字节为单位存储对象或类型的存储尺寸。下面举例获取任何机器上 int 类型的存储尺寸: using System;namespace DataTypeApplication {class Program{…...

结构化输出及其使用方法
在 LLM 应用程序中构建稳健性和确定性 图片来自作者 欢迎来到雲闪世界。OpenAI最近宣布其最新的gpt-4o-2024–08–06模型支持结构化输出。与大型语言模型 (LLM) 相关的结构化输出并不是什么新鲜事——开发人员要么使用各种快速工程技术,要么使用第三方工具。 在本文…...

yolov8人脸识别案例
GitHub - wangWEI201901/YOLOv8-Detection-Project: 🛣️基于YOLOv8的智慧校园人脸识别和公路汽车检测...
成员变量在Java中的定义与使用
成员变量在Java中的定义与使用 大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在本文中,我们将详细探讨Java中的成员变量,包括其定义、使用以及各种类型的成员变量示例。 成员…...

Python开发工具PyCharm入门指南 - 用户界面主题更改
JetBrains PyCharm是一种Python IDE,其带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具。此外,该IDE提供了一些高级功能,以用于Django框架下的专业Web开发。 界面主题定义了窗口、对话框、按钮和用户界面的所有可视元素的外观…...
TCP网络套接字
一、创建套接字 #include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol); 参数: domain:指定使用的协议族。常见的取值有AF_INET(IPv4)和AF_INET6(IPv6&a…...

Element学习(axios异步加载数据、案例操作)(5)
1、这次学习的是上次还未完成好的恶element案例,对列表数据的异步加载,并渲染展示。 ——>axios来发送异步请求 (1) (2)在vue当中安装axios (注意在当前的项目目录,并且安装完之后…...

大数据-65 Kafka 高级特性 分区 Broker自动再平衡 ISR 副本 宕机恢复再重平衡 实测
点一下关注吧!!!非常感谢!!持续更新!!! 目前已经更新到了: Hadoop(已更完)HDFS(已更完)MapReduce(已更完&am…...

html+css+js网页设计 软通动力网站2个页面(带js)首页轮播图+置顶导航
htmlcssjs网页设计 软通动力网站2个页面(带js)首页轮播图置顶导航 网页作品代码简单,可使用任意HTML编辑软件(如:Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及…...

【经验分享】ShardingSphere+Springboot-04:自定义分片算法(COMPLEX/STANDARD)
文章目录 3.4 CLASS_BASED 自定义类分片算法3.4.1 复杂分片自定义算法(strategyCOMPLEX )3.4.2 STANDARD 标准分片自定义算法## 进阶:star: 自定义算法范围查询优化 3.4 CLASS_BASED 自定义类分片算法 3.4.1 复杂分片自定义算法(strategyCOM…...
如何设置RabbitMQ和Redis消息队列系统
设置RabbitMQ和Redis作为消息队列系统时,需要分别进行安装、配置和测试,以确保它们能够正常工作并满足你的应用需求。以下是一个基于这两个系统的设置指南: RabbitMQ的设置 1. 安装Erlang 由于RabbitMQ是用Erlang语言编写的,因…...
白骑士的Matlab教学高级篇 3.3 工具箱与扩展
MATLAB 提供了丰富的工具箱(Toolbox)和扩展功能,这些工具箱涵盖了各个领域的专业计算需求,如信号处理、图像处理、统计与机器学习等。利用工具箱,用户可以快速实现复杂的计算和分析任务。本文将介绍常用的工具箱及其使…...

bug: 配置flyway.locations多个脚本位置不生效
文章目录 业务场景场景一场景二 业务场景 随着项目版本迭代,数据库结构也会变动。如果一个项目引用其他项目的jar包,并且需要执行对应jar包的flyway脚本,就需要配置flyway.locations 场景一 正常情况下,在一个项目中可以在yml文件…...
8月5日SpringBoot学习笔记
今日内容:搭建mybatis ORM 配置数据源 $#的区别 增删改查 搭建mybatis 在原有maven项目基础配置上进行: pom文件添加依赖 <!-- Mybatis --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-…...

Java学习笔记(二十):反射、动态代理、日志、类加载器、xml、单元测试Junit、注解
目录 一、反射 1.1 反射的概述: 1.2 学习反射到底学什么? 1.3 获取字节码文件对象的三种方式 1.4 字节码文件和字节码文件对象 1.5 获取构造方法 1.6 获取构造方法并创建对象 1.7 获取成员变量 1.8 获取成员变量并获取值和修改值 1.9 获取成员…...

web3-基于贝尔曼福特算法(Bellman-Ford )与 SMT 的 Web3 DeFi 套利策略研究
web3-基于贝尔曼福特算法(Bellman-Ford )与 SMT 的 Web3 DeFi 套利策略研究 如何找到Defi中的交易机会 把defi看做是一个完全开放的金融产品图表,可以看到所有的一切东西;我们要沿着这些金融图表找到一些最优的路径,就…...
前端八股之JS的原型链
1.原型的定义 每一个对象从被创建开始就和另一个对象关联,从另一个对象上继承其属性,这个另一个对象就是 原型。 当访问一个对象的属性时,先在对象的本身找,找不到就去对象的原型上找,如果还是找不到,就去…...
在Ubuntu上使用 dd 工具制作U盘启动盘
在Ubuntu上使用 dd 工具制作U盘启动盘 在Linux系统中,dd 是一个功能强大且原生支持的命令行工具,常用于复制文件和转换数据。它也可以用来将ISO镜像写入U盘,从而创建一个可启动的操作系统安装盘。虽然图形化工具(如 Startup Disk…...
C#合并CAN ASC文件:实现与优化
C#合并CAN ASC文件:实现与优化 在汽车电子和工业控制领域,CAN(Controller Area Network)总线是一种广泛使用的通信协议。CAN ASC(American Standard Code)文件则是记录CAN总线通信数据的标准格式ÿ…...

什么是梯度磁场
梯度磁场是叠加在均匀主磁场(如MRI中的静磁场B₀)上的一种特殊磁场,其强度会沿着特定方向(如X、Y或Z轴)呈线性变化。这种磁场在磁共振成像和粒子控制等领域发挥着关键作用,主要用于实现空间位置的精确编码和…...
并行硬件环境及并行编程
文章目录 A1. (并行编程 基于的)硬件环境 的 基本模型A2. 特定的硬件实现B1. 并行编程基本模型与编程技术✅ 并行编程的一般流程**第一阶段:基于“编程直觉模型”设计程序****第二阶段:程序编译并部署到实际硬件** B2.特定的 硬件环境下的 并行编程 A1. …...
Windows 系统安装 Redis 详细教程
Windows 系统安装 Redis 详细教程 一、Redis 简介 Redis(Remote Dictionary Server)是一个开源的、基于内存的高性能键值存储系统,常被用作数据库、缓存和消息中间件。相比传统数据库,Redis 具有以下优势: 超高性能…...
C#提取CAN ASC文件时间戳:实现与性能优化
C#提取CAN ASC文件时间戳:实现与性能优化 在汽车电子和工业控制领域,CAN总线是最常用的通信协议之一。而ASC(ASCII)文件作为CAN总线数据的标准日志格式,广泛应用于数据记录和分析场景。本文将深入探讨如何高效地从CAN…...
Redis 与 MySQL 数据一致性保障方案
在高并发场景下,Redis 作为缓存中间件与 MySQL 数据库配合使用时,数据一致性是一个关键挑战。本文将详细探讨如何保障 Redis 与 MySQL 的数据一致性,并结合 Java 代码实现具体方案。 数据不一致的原因分析 在分布式系统中,Redis…...

【数据结构】6. 时间与空间复杂度
文章目录 一、算法效率1、算法的复杂度 二、时间复杂度1、时间复杂度的概念2、大O的渐进表示法3、常见时间复杂度计算1)实例12)实例23)实例34)实例45)实例56)实例67)实例78)实例8 三…...