线程同步学习
概念
有A、B、C三个线程,A线程负责输入数据,B线程负责处理数据、C线程负责输出数据,这三个线程之间就存在着同步关系,即A必须先执行,B次之,C最后执行,否则不能得到正确的结果。
那么所谓线程同步,是指多个线程在发生的事件存在着某种时序关系,它们必须按规定时间执行,以共同完成一项任务。多个线程在访问共享资源时,通过一定的机制来协调它们的执行顺序,以确保共享资源在任何时刻都能被正确地访问和修改。
为什么需要线程同步呢?
在多线程编程中,不同的线程可能会同时访问和修改同一个共享资源。如果没有适当的同步机制,可能会导致数据不一致、资源竞争等问题。例如,两个线程同时对一个计数器进行递增操作,如果不进行同步,可能会导致计数器的值不正确。
还记得上一篇博客中讲过的一个知识点就是线程的竞争能力会有不同,竞争能力强的线程可能从头到尾都占用一个锁,所以线程同步是来解决这种情况的。实现线程同步的方法主要有三种,分别是互斥锁、信号量和条件变量。本博客主要是讲解使用条件变量的方法来实现线程同步。
条件变量
当一个线程互斥地访问某个变量时,它可能发现在其它线程改变状态之前,它什么也做不了。例如一个线程访问队列时,发现队列为空,它只能等待,直到其它线程将一个节点添加到队列中,这种情况就需要用到条件变量。条件变量通常与互斥锁一起使用,用于线程之间的等待和通知。
当一个线程需要等待某个条件满足时,它可以使用条件变量进行等待。在等待之前,线程必须先获取互斥锁,以确保对共享资源的访问是安全的。
条件变量的函数接口跟互斥锁的基本一样,定义方式也一样,可以局部或者全局定义。它存在于<pthread.h>
头文件中,类型是pthread_cond_t
。
全局定义
函数原型:pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
变量名可以自己定义,全局的条件变量不需要手动销毁。
局部定义
条件变量的局部定义需要自己手动创建和销毁,这些都需要函数接口来实现。我们接下来就来学习这些接口。
pthread_cond_init
功能:用于初始化一个条件变量。
函数原型:int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
参数:
cond
:要初始化的条件变量,类型是pthread_cond_t *
的指针。attr
:条件变量的属性,一般设置为nullptr
即可。
返回值:成功返回0,失败返回错误码。
pthread_cond_destory
功能:用于销毁一个条件变量。
函数原型:int pthread_cond_destroy(pthread_cond_t *cond);
返回值:成功返回0,失败返回错误码。
pthread_cond_wait
功能:用于让一个线程进入等待队列等待,直到被唤醒。
函数原型:int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
参数:
cond
:指向条件变量的指针。mutex
:指向互斥锁的指针。在调用pthread_cond_wait
之前,线程必须已经持有这个互斥锁。传入锁的指针是为了帮助这个线程释放该锁,从而让其他线程也能够轻松申请锁进入等待队列等待。
返回值:成功返回0,失败返回错误码。
进入到等待队列之后,可以有2种方式唤醒队列中的线程。分别是唤醒一个线程和唤醒所有线程。
pthread_cond_signal
功能:唤醒等待队列中的第一个线程。
函数原型:int pthread_cond_signal(pthread_cond_t *cond);
返回值:成功返回0,失败返回错误码。
pthread_cond_broadcast
功能:唤醒等待队列中的所有线程。
函数原型:int pthread_cond_broadcast(pthread_cond_t *cond);
接下来,我将用图片的方式来帮助大家理解条件变量函数接口的使用方法。
如图所示,有三个线程和一个临界资源,现在线程都要去争夺临界资源。
线程1先申请到了锁,但是我们给临界资源添加了条件变量,所以线程1不能直接进入到临界资源,而是要先到等待队列当中去,并且要释放锁。
线程2和线程3也是一样,都需要先申请锁,然后发现我们给临界资源添加了条件变量,所以要先去等待队列当中去,并且释放锁。
现在所有的线程都进入到队列当中了,先加入到等待队列是为了保持线程同步。也就是谁先访问的临界资源,最后谁就第一个访问。还记得上一篇博客中举的VIP自习室的例子吗
绿色代表的是已经在等待队列当中的线程了,红色代表的是新来的线程,他要先到自习室的门口,发现自习室里面有人,于是他需要排到队列的尾部去,直到轮到他进入到临界资源当中。而自习室当中的人要是临时有事,需要离开,那么他要先把钥匙归还并且还需要摇响铃铛,告诉下一个人该到他自习了,当解决完事情之后,需要重新排队才行。
如果使用pthread_cond_signal
接口唤醒队列的第一个线程,那么线程就可以重新获得之前的锁,进入到临界资源当中去。
假设线程1执行完临界区的代码之后,又重新申请了锁,由于条件变量的存在,线程1不能直接访问临界资源,必须要到等待队列的尾部才行。这样就能避免一个线程一直访问临界资源。
如果使用pthread_cond_broadcast
接口唤醒所有的线程,那么就会让所有的线程再次竞争同一把锁,谁先竞争到谁就访问临界资源,当访问完毕后,剩下的线程继续竞争,再访问临界资源。
现在通过代码来理解这些接口有什么作用。
int cnt = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;void *Count(void *args)
{pthread_detach(pthread_self());uint64_t number = (uint64_t)args;cout << "pthread: " << number << "create sucess" << endl;while (true){pthread_mutex_lock(&mutex);pthread_cond_wait(&cond, &mutex);cout << "pthread: " << number << ", cnt: " << cnt++ << endl;pthread_mutex_unlock(&mutex);}
}int main()
{for (uint32_t i = 0; i < 5; i++){pthread_t tid;pthread_create(&tid, nullptr, Count, (void *)&i);usleep(1000);}sleep(3);cout << "main thread ctrl begin: " << endl;while (1){sleep(1);pthread_cond_signal(&cond);// pthread_cond_broadcast(&cond);cout << "signal one thread..." << endl;}return 0;
}
先创建一个全局变量cnt
用来观察每个线程的变化,然后再全局初始化mutex
和cond
。在主函数当中,创建了5个线程,休眠3秒后,接着在循环当中每过一秒使用signal
接口唤醒队列当中的每一个线程,而线程执行的函数Count
,进入while循环后,通过pthread_mutex_lock
加锁,试图访问临界资源。但是我们使用了条件变量进行限制,需要先通过pthread_cont_wait
进入等待队列,并且释放掉申请的锁,唤醒线程则是到主线程当中的pthread_cond_signal
接口来唤醒,每过一秒钟唤醒一次。
然后我们来看代码结果:
这分别是用2个唤醒接口运行出来的结果,我们可以看到signal
接口,每秒钟唤醒一个接口,5个线程都唤醒后,又重新开始;而broadcast
接口,一次唤醒所有的线程,也可以看到第一次时3号线程的竞争能力强,第二次时0号线程的竞争能力强,但可以确定的是,每个轮次中,每个线程都获得了一次临界资源,这也算是线程同步。
相关文章:
线程同步学习
概念 有A、B、C三个线程,A线程负责输入数据,B线程负责处理数据、C线程负责输出数据,这三个线程之间就存在着同步关系,即A必须先执行,B次之,C最后执行,否则不能得到正确的结果。 那么所谓线程同…...
十二、Hive 函数
作者:IvanCodes 日期:2025年5月17日 专栏:Hive教程 在数据处理的广阔天地中,我们常常需要对数据进行转换、计算、清洗或提取特定信息。Hive 提供了强大的内置运算符和丰富的内置函数库,它们就像魔法师手中的魔法棒&…...
DeepSeek 赋能社会科学:解锁研究新范式
目录 一、DeepSeek:大语言模型中的新力量1.1 DeepSeek 技术亮点1.2 与其他模型对比 二、DeepSeek 在社会科学研究中的应用领域2.1 经济学研究2.2 社会学研究2.3 历史学研究2.4 法学研究 三、DeepSeek 应用案例深度剖析3.1 案例一:社会学研究中社会舆情分…...
java函数内的变量问题
public class VendingMachine {//设计一个类叫做VendingMachine,用这个类制造一个对象vmint price 80;int balance;//三个属性int total;void showprompt(){System.out.println("Welcome");}void insertmoney(int amount){balance balance amount;}void showBalan…...
docker部署第一个Go项目
1.前期准备 目录结构 main.go package mainimport ("fmt""github.com/gin-gonic/gin""net/http" )func main() {fmt.Println("\n .::::.\n .::::::::.\n :::::::::::\n …...
【读代码】端到端多模态语言模型Ultravox深度解析
一、项目基本介绍 Ultravox是由Fixie AI团队开发的开源多模态大语言模型,专注于实现音频-文本的端到端实时交互。项目基于Llama 3、Mistral等开源模型,通过创新的跨模态投影架构,绕过了传统语音识别(ASR)的中间步骤,可直接将音频特征映射到语言模型的高维空间。 核心优…...
管理前端项目依赖版本冲突导致启动失败的问题的解决办法
管理前端项目依赖版本冲突导致启动失败的问题,可按照以下步骤系统解决: 1. 定位冲突来源 查看错误日志:启动失败时的控制台报错通常会指出具体模块或版本问题,例如 Module not found 或 TypeError。检查依赖树:npm l…...
北京市工程技术人才职称评价基本标准条件解读
北京市工程技术人才职称评价基本标准条件 北京市工程技术人才之技术员 北京市工程技术人才之助理工程师 北京市工程技术人才之工程师 北京市工程技术人才之高级工程师 北京市工程技术人才之高级工程师(破格) 北京市工程技术人才之正高级工程师 北京市工程…...
MUSE Pi Pro 开发板 Imagination GPU 利用 OpenCL 测试
视频讲解: MUSE Pi Pro 开发板 Imagination GPU 利用 OpenCL 测试 继续玩MUSE Pi Pro,今天看下比较关注的gpu这块,从opencl看起,安装clinfo指令 sudo apt install clinfo 可以看到这颗GPU是Imagination的 一般嵌入式中gpu都和hos…...
Mysql数据库之集群进阶
一、日志管理 5.7版本自定义路径时的文件需要自己提前创建好文件,不会自动创建,否则启动mysql会报错 错误日志 rpm包(yum) /var/log/mysql.log 默认错误日志 ###查询日志路径 [rootdb01 ~]# mysqladmin -uroot -pEgon123 variables | grep -w log_e…...
JavaScript防抖与节流全解析
文章目录 前言:为什么需要防抖和节流基本概念与区别防抖(Debounce)节流(Throttle)关键区别防抖(Debounce)详解1. 基本防抖函数实现2. 防抖函数的使用3. 防抖函数的工作流程4. 防抖函数进阶 - 立即执行选项节流(Throttle)详解1. 基本节流函数实现时间戳法(第一次会立即执行)定…...
大模型学习:Deepseek+dify零成本部署本地运行实用教程(超级详细!建议收藏)
文章目录 大模型学习:Deepseekdify零成本部署本地运行实用教程(超级详细!建议收藏)一、Dify是什么二、Dify的安装部署1. 官网体验2. 本地部署2.1 linux环境下的Docker安装2.2 Windows环境下安装部署DockerDeskTop2.3启用虚拟机平台…...
在RK3588上使用NCNN和Vulkan加速ResNet50推理全流程
在RK3588上使用NCNN和Vulkan加速ResNet50推理全流程 前言:为什么需要关注移动端AI推理一、环境准备与框架编译1.1 获取NCNN源码1.2 安装必要依赖1.3 编译NCNN二、模型导出与转换2.1 生成ONNX模型2.2 转换NCNN格式三、模型量化加速3.1 生成校准数据3.2 执行量化操作四、性能测试…...
Web安全基础:深度解析与实战指南
一、Web安全体系架构的全面剖析 1.1 分层防御模型(Defense in Depth) 1.1.1 网络层防护 防火墙技术: 状态检测防火墙(SPI):基于连接状态跟踪,阻断非法会话(如SYN Flood攻击)下一代防火墙(NGFW):集成IPS、AV、URL过滤(如Palo Alto PA-5400系列)配置示例…...
Uniapp开发鸿蒙应用时如何运行和调试项目
经过前几天的分享,大家应该应该对uniapp开发鸿蒙应用的开发语法有了一定的了解,可以进行一些简单的应用开发,今天分享一下在使用uniapp开发鸿蒙应用时怎么运行到鸿蒙设备,并且在开发中怎么调试程序。 运行 Uniapp项目支持运行到…...
Python海龟绘图(Turtle Graphics)核心函数和关键要点
以下是Python海龟绘图(Turtle Graphics)的核心函数和关键要点整理: 一、画布设置 函数/方法说明参数说明备注turtle.setup(width, height, x, y)设置画布尺寸和位置width宽度,height高度,x/y窗口左上角坐标默认尺寸80…...
如何在Cursor中高效使用MCP协议
1、Cursor介绍 Cursor是一个功能强大的开发工具,内置了聊天助手、代码自动补全和调试工具,能够与多种外部工具和服务(如数据库、文件系统、浏览器等)进行深度集成。借助MCP(Multiverse Communication Protocol&#x…...
典籍知识问答模块AI问答bug修改
一、修改流式数据处理问题 1.问题描述:由于传来的数据形式如下: event:START data:350 data:< data:t data:h data:i data:n data:k data:> data: data: data: data: data:嗯 data:, 导致需要修改获取正常的当前信息id并更…...
Redis 发布订阅模式深度解析:原理、应用与实践
在现代分布式系统架构中,实时消息传递机制扮演着至关重要的角色。Redis 作为一款高性能的内存数据库,其内置的发布订阅(Pub/Sub)功能提供了一种轻量级、高效的消息通信方案。本文将全面剖析 Redis 发布订阅模式,从其基本概念、工作原理到实际…...
通义千问-langchain使用构建(三)
目录 序言docker 部署xinference1WSL环境docker安装2拉取镜像运行容器3使用的界面 本地跑chatchat1rag踩坑2使用的界面2.1配置个前置条件然后对话2.2rag对话 结论 序言 在前两天的基础上,将xinference调整为wsl环境,docker部署。 然后langchain chatcha…...
c++ 仿函数
示例代码: void testFunctor() {using Sum struct MyStruct {int operator() (int a, int b) const { // 重载()运算符return a b;}};Sum sum;std::cout << sum(9528, -1) << std::endl; } 打印: 仿函数意思是&am…...
hyper-v 虚拟机怎么克隆一台一样的虚拟机?
环境: hyper-v Win10专业版 问题描述: hyper-v 虚拟机怎么克隆一台一样的虚拟机? 解决方案: 以下是在 Hyper-V 中克隆虚拟机的几种方法: 方法一:使用导出和导入功能 导出虚拟机: 打开 H…...
操作系统:os概述
操作系统:OS概述 程序、进程与线程无极二级目录三级目录 程序、进程与线程 指令执行需要那些条件?CPU内存 需要数据和 无极 二级目录 三级目录...
【技巧】GoogleChrome浏览器开发者模式查看dify接口
回到目录 GoogleChrome浏览器开发者模式查看dify接口 1.搭建本地dify开发环境 参考 《 win10的wsl环境下调试dify的api后端服务(20250511发布)》 2.打开dify首页,进入开发者模式,Network页 勾选 Preserve log [图1] 3.填好用户名和密码,…...
Ocean: Object-aware Anchor-free Tracking
领域:Object tracking It aims to infer the location of an arbitrary target in a video sequence, given only its location in the first frame 问题/现象: Anchor-based Siamese trackers have achieved remarkable advancements in accuracy, yet…...
java中的循环结构
文章目录 流程控制顺序结构if单选择结构if双选择结构if多选择结构嵌套的if结构switch多选择结构 循环结构while循环do...while循环 for循环增强for循环 break continue练习案例 流程控制 顺序结构 java的基本结果就是顺序结构,除非特别指明,否则就按照…...
数学复习笔记 16
前言 例题真是经典。 background music 《青春不一样》 2.28 算一个行列式,算出来行列式不等于零,这表示矩阵式可逆的。但是这个算的秩是复合的,感觉没啥好办法了,我直接硬算了,之后再看解析积累好的方法。算矩阵…...
PySide6 GUI 学习笔记——常用类及控件使用方法(常用类颜色QColor)
文章目录 一、概述二、核心功能三、常用函数及方法四、代码示例五、注意事项 一、概述 QColor 是用于处理颜色的类,支持 RGB、HSV、HSL、CMYK 等多种颜色模型,提供颜色创建、转换、分量操作及格式转换功能。支持透明度设置,可通过颜色名称或…...
【Closure-Hayd】
RNA序列本身存在结构上的物理信息,因此可以利用文献提供的相关方法来对RNA序列的物理特征进行更加细致的提取。 几何向量编码(GVP模块)借鉴Rhodesign模型中的GVP(Geometric Vector Perceptron)模块,将每个…...
MySQL高可用架构
一、读写分离在高可用架构中的核心作用 1.读写分离与高可用的协同价值 在MySQL高可用架构中,读写分离不仅是性能优化的手段,更是提升系统容错能力的关键策略。通过将写操作(INSERT、UPDATE、DELETE) 集中到主节点,读…...
粒子群算法(PSO算法)
粒子群算法概述 1.粒子群优化算法(Particle Swarm Optimization,简称PSO)。粒子群优化算法是在1995年由Kennedy博士和Eberhart博士一起提出的,它源于对鸟群捕食行为的研究。 2.基本核心是利用群体中的个体对信息的共享从而使得整…...
信道编码技术介绍
信息与通信系统中的编码有4 种形式:信源编码、信道编码、密码编码和多址编码。 其中信道编码的作用是对信源经过压缩后的数据加一定数量受到控制的冗余,使得数据在传输中或接收中发生的差错可以被纠正或被发现,从而可以正确恢复出原始数据信息…...
JavaScript【4】数组和其他内置对象(API)
1.数组: 1.概述: js中数组可理解为一个存储数据的容器,但与java中的数组不太一样;js中的数组更像java中的集合,因为此集合在创建的时候,不需要定义数组长度,它可以实现动态扩容;js中的数组存储元素时,可以存储任意类型的元素,而java中的数组一旦创建后,就只能存储定义类型的元…...
【背包dp-----分组背包】------(标准的分组背包【可以不装满的 最大价值】)
通天之分组背包 题目链接 题目描述 自 01 01 01 背包问世之后,小 A 对此深感兴趣。一天,小 A 去远游,却发现他的背包不同于 01 01 01 背包,他的物品大致可分为 k k k 组,每组中的物品相互冲突,现在&a…...
docker-compose——安装mongo
编写docker-compose.yml version : 3.8services:zaomeng-mongodb:container_name: zaomeng-mongodbimage: mongo:latestrestart: alwaysports:- 27017:27017environment:- MONGO_INITDB_ROOT_USERNAMEroot- MONGO_INITDB_ROOT_PASSWORDpssw0rdvolumes:- ./mongodb/data:/data/…...
day 28
类 一个常见的类的定义包括了: 1. 关键字class 2. 类名 3. 语法固定符号冒号(:) 4. 一个初始化函数__init__(self) Pass占位符和缩进 Python 通过缩进来定义代码块的结构。当解释器遇到像 def, class, if, for 这样的语句,并且后面跟着冒号 : 时&…...
JavaScript入门【1】概述
1.JavaScript是什么? <font style"color:rgb(38,38,38);">Javascript (简称“JS”)是⼀种直译式脚本语⾔,⼀段脚本其实就是⼀系列指令,计算机通过这些指令来达成⽬标。它⼜是⼀种动态类型的编程语⾔。JS⽤来在⽹…...
MySQL 中 JOIN 和子查询的区别与使用场景
目录 一、JOIN:表连接1.1 INNER JOIN:内连接1.2 LEFT JOIN:左连接1.3 RIGHT JOIN:右连接1.4 FULL JOIN:全连接二、子查询:嵌套查询2.1 WHERE 子句中的子查询2.2 FROM 子句中的子查询2.3 SELECT 子句中的子查询三、JOIN 和子查询的区别3.1 功能差异3.2 性能差异3.3 使用场…...
DeepSeek 大模型部署全指南:常见问题、优化策略与实战解决方案
DeepSeek 作为当前最热门的开源大模型之一,其强大的语义理解和生成能力吸引了大量开发者和企业关注。然而在实际部署过程中,无论是本地运行还是云端服务,用户往往会遇到各种技术挑战。本文将全面剖析 DeepSeek 部署中的常见问题,提…...
Python 3.11详细安装步骤(包含安装包)Python 3.11详细图文安装教程
文章目录 前言Python 3.11介绍Python 3.11安装包下载Python 3.11安装步骤 前言 作为当前最热门的编程语言之一,Python 3.11 不仅拥有简洁优雅的语法,还在性能上实现了飞跃,代码运行速度提升显著。无论是初入编程的小白,还是经验丰…...
虚拟主播肖像权保护,数字时代的法律博弈
首席数据官高鹏律师团队 在虚拟主播行业蓬勃发展的表象之下,潜藏着一场关乎法律边界的隐形战争。当一位虚拟偶像的3D模型被非法拆解、面部数据被批量复制,运营方惊讶地发现——传统的肖像权保护体系,竟难以完全覆盖这具由代码与数据构成的“…...
硬件工程师笔记——二极管Multisim电路仿真实验汇总
目录 1 二极管基础知识 1.1 工作原理 1.2 二极管的结构 1.3 PN结的形成 1.4 二极管的工作原理详解 正向偏置 反向偏置 multisim使用说明链接 2 二极管特性实验 2.1 二极管加正向电压 2.2 二极管加反向电压 2.3 二极管两端的电阻 2.4 交流电下二级管工作 2.5 二极…...
学习笔记(C++篇)—— Day 6
1.内部类 如果一个类定义在另一个类的内部,就叫做内部类。 例如下面一个代码示例: class A { private:static int _k;int _h 1; public:class B // B默认就是A的友元{public:void foo(const A& a){cout << _k << endl; //OKcout <&…...
常见的实时通信技术(轮询、sse、websocket、webhooks)
1. HTTP轮询:最老实的办法 刚开始做实时功能时,我第一个想到的就是轮询。特别简单直白,就像你每隔5分钟就刷新一次朋友圈看看有没有新消息一样。 短轮询:勤快但费劲 短轮询就是客户端隔三差五地问服务器:"有新…...
2025年第三届盘古石杯初赛(智能冰箱,监控部分)
前言 所以去哪里可以取到自己家里的智能家居数据呢???? IOT物联网取证 1、分析冰箱,请问智能冰箱的品牌? [答案格式:xiaomi] Panasonic2、请问智能冰箱的型号? [答案格式&#x…...
[强化学习的数学原理—赵世钰老师]学习笔记02-贝尔曼方程
本人为强化学习小白,为了在后续科研的过程中能够较好的结合强化学习来做相关研究,特意买了西湖大学赵世钰老师撰写的《强化学习数学原理》中文版这本书,并结合赵老师的讲解视频来学习和更深刻的理解强化学习相关概念,知识和算法技…...
基于STM32的INA226电压电流检测仪
系统总体框图 功率检测装置原理图功能及模块连接说明 一、系统功能概述 该装置以STM32F103C8T6微控制器为核心,集成功率检测、数据交互、状态显示和用户提示功能,通过模块化设计实现稳定运行。 二、各模块功能及连接方式 按键模块 功能:…...
Android7 Input(七)App与input系统服务建立连接
概述 本文主要讲述Android 系统创建窗口时与输入管理系统服务通过InputChannel通道建立通信桥梁的过程。 本文涉及的源码路径 frameworks/native/libs/input/InputTransport.cpp frameworks/base/core/java/android/view/InputChannel.java frameworks/base/core/java/andr…...
1.2 C++第一个程序
第一个程序:Hello World 教程 目标 用 cout 输出文字,学会用 endl 换行。理解程序的基本结构,明白 main 函数的作用。 一、程序是什么?——像“魔法食谱” 比喻:写程序就像写一份做蛋糕的食谱! 食材&am…...
Hi3516DV500刷写固件
hi3516DV500刷固件 1、硬件连接 2、软件准备 3、刷固件步骤 一、硬件连接 特别注意的是,串口的接线顺序 通过网线连接好笔记本和开发板后,需要确认一下网口水晶头是否闪烁,以确认网络物理是否连通 二、软件资源准备 固件包准备 打开工具…...