递归锁与普通锁的区别
什么是锁?
在多线程编程中,锁是一种机制,用来确保某些代码块在同一时间只能被一个线程执行。想象一下,你和你的朋友们都想同时进入一个只有一把椅子的房间。为了避免混乱,你们需要一个锁来控制进入的顺序。
普通锁(Lock)
普通锁就像是一个简单的门锁。你拿到钥匙(获取锁),进了房间(执行代码),然后记得把钥匙放回去(释放锁),这样别人才能进来。
让我们看看Python中的普通锁是如何工作的:
import threadinglock = threading.Lock()def critical_section():with lock:print(f"{threading.current_thread().name} has entered the critical section")# 模拟一些工作import timetime.sleep(1)print(f"{threading.current_thread().name} is leaving the critical section")threads = []
for i in range(3):thread = threading.Thread(target=critical_section)threads.append(thread)thread.start()for thread in threads:thread.join()
在这个例子中,我们创建了一个普通锁,并在critical_section函数中使用它。每个线程在进入关键区之前都会获取锁,并在离开时释放锁。这样可以确保同一时间只有一个线程在执行关键区的代码。
普通锁的死锁场景
普通锁虽然简单高效,但在某些情况下会导致死锁。让我们看看一个死锁的例子:
import threadinglock = threading.Lock()def deadlock_function():lock.acquire()print(f"{threading.current_thread().name} has acquired the lock")# 尝试再次获取同一把锁,导致死锁lock.acquire()print(f"{threading.current_thread().name} has acquired the lock again")lock.release()lock.release()thread = threading.Thread(target=deadlock_function)
thread.start()
thread.join()
在这个例子中,deadlock_function函数尝试两次获取同一把锁。第一次获取锁成功,但第二次获取锁时,由于锁已经被当前线程持有,导致死锁。程序会卡在第二次获取锁的地方,无法继续执行。
递归锁(Reentrant Lock)
递归锁就像是一个聪明的门锁,它知道你已经在房间里了,所以如果你再试图进入,它会让你进去,而不会把你锁在外面。这在递归函数或需要多次获取同一把锁的情况下特别有用。
让我们看看递归锁是如何工作的:
import threadingrlock = threading.RLock()def recursive_function(level):with rlock:print(f"{threading.current_thread().name} has entered level {level}")if level > 0:recursive_function(level - 1)print(f"{threading.current_thread().name} is leaving level {level}")thread = threading.Thread(target=recursive_function, args=(3,))
thread.start()
thread.join()
在这个例子中,我们使用了递归锁RLock。recursive_function函数会递归调用自己,并在每个递归层级获取同一把锁。递归锁允许同一个线程多次获取锁,而不会导致死锁。
递归锁 vs 普通锁
- 普通锁:简单高效,但同一个线程不能多次获取同一把锁,否则会导致死锁。
- 递归锁:允许同一个线程多次获取同一把锁,适用于递归调用或需要多次获取锁的情况,但开销稍大。
更清晰的案例
递归锁:
import threadingrecursive_lock = threading.RLock()def recursive_function(n):if n <= 0:returnrecursive_lock.acquire()print(f"Acquired lock, n={n}")recursive_function(n-1)recursive_lock.release()print(f"Released lock, n={n}")recursive_function(3)
输出:
Acquired lock, n=3
Acquired lock, n=2
Acquired lock, n=1
Released lock, n=1
Released lock, n=2
Released lock, n=3
普通锁:
import threadingrecursive_lock = threading.Lock()def recursive_function(n):if n <= 0:returnrecursive_lock.acquire()print(f"Acquired lock, n={n}")recursive_function(n-1)recursive_lock.release()print(f"Released lock, n={n}")recursive_function(3)
运行一天的输出:
Acquired lock, n=3
结论:
锁在多线程编程中是必不可少的工具。普通锁适用于简单的同步场景,而递归锁则在复杂的递归或多次锁定场景中大显身手。
相关文章:
递归锁与普通锁的区别
什么是锁? 在多线程编程中,锁是一种机制,用来确保某些代码块在同一时间只能被一个线程执行。想象一下,你和你的朋友们都想同时进入一个只有一把椅子的房间。为了避免混乱,你们需要一个锁来控制进入的顺序。 普通锁&a…...
FPGA上板项目(二)——PLL测试
目录 实验内容实验原理实验步骤实验结果 实验内容 将差分时钟信号转化为 192MHz 时钟信号作为输出。 实验原理 PLL,即锁相环,一种反馈控制电路,具有时钟倍频、分频、相位偏移和可编程占空比的功能。 实验步骤 添加 clocking wizard IP核&…...
C语言 | Leecode C语言题解之第229题多数元素II
题目: 题解: /*** Note: The returned array must be malloced, assume caller calls free().*//*假定 num1,num2 为出现次数大于 nums.length / 3 的两个数。(最多出现两个)遍历 nums, 若出现 num1、num2…...
mybatis-plus映射mysql的json类型的字段
一、对json里面内容建立实体类 Data AllArgsConstructor NoArgsConstructor public class RouteMetaEntity {private String title;private Boolean affix;private Boolean isAlwaysShow; }二、主类做映射 TableField(typeHandler JacksonTypeHandler.class)private RouteMe…...
20240716 Codeforces题目
A - Split the Multiset 题目 多集是一组数字,其中可以有相等的元素,数字的顺序无关紧要。例如, { 2 , 2 , 4 } \{2,2,4\} {2,2,4} 是一个multiset。 你有一个多集 S S S 。最初,multiset只包含一个正整数 n n n 。即 S {…...
29.【C语言】自定义函数
1、自定义详解 *提示:先看第12,19篇 例:写一个程序交换两个变量的值 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> void swap(int x, int y) {int z 0;z x;x y;y z; } int main() {int a 10;int b 20;swap(a, b);printf("%d…...
C++面向对象编程 基础篇(3)函数基础
3、函数基础 3.1 函数默认参数 在C中,函数的形参列表中的形参是可以有默认值的 注意事项: 如果某个位置已经有了默认参数,往后的形参都要有默认参数 函数声明和函数实现只能有一个有默认参数 示例: //如果自己传入参数&…...
excel有条件提取单元格特定文本(筛选纯文字的单元格或含有数字的单元格、单元格提取不同的文本长度)
实际工作背景 需要对导出的银行流水中的数十个村以及对应的村小组进行分组统计,但是初始的表格中村和小组是混在一起的,如下图所示: 目的:将大树村和大树村小组名称分别筛选出来 1.观察发现,大树村小组的单元格第4…...
HBase 在统一内容平台业务的优化实践
作者:来自 vivo 互联网服务器团队-Leng Jianyu、Huang Haitao HBase是一款开源高可靠性、扩展性、高性能和灵活性的分布式非关系型数据库,本文围绕数据库选型以及使用HBase的痛点展开,从四个方面对HBase的使用进行优化,取得了一些…...
【异常解决】Unable to start embedded Tomcat Nacos 启动报错
Unable to start embedded Tomcat Nacos 启动报错解决方案 一、背景描述二、原因分析三、解决方案 一、背景描述 Windows 本地启动 Nacos(2.2.0) 服务,控制台报错 Unable to start embedded Tomcat。 报错信息:Unable to start …...
【Java面向对象】对象和类
文章目录 1.为对象定义类2.定义类2.1 主类 3.类与对象3.1 构造方法3.2 通过引用变量访问对象3.3 访问对象的数据和方法3.4 引用数据域和 null 值3.5 基本类型变量和引用类型变量的区别 4.常见的类 1.为对象定义类 面向对象程序设计(OOP) 就是使用对象进行程序设计。对象 (obje…...
在微服务架构架构中父工程中的`<dependencyManagement>`和 `<dependencies>`的区别
在微服务架构架构中父工程中的<dependencyManagement>和 <dependencies>的区别: 在微服务架构中,通常会有一个父工程(或称作聚合工程)来管理一组相关的子模块(即各个微服务)。Maven 的 <de…...
Docker安装Zookeeper、RocketMQ
安装Zookeeper 拉取镜像 docker pull zookeeper:3.9.2启动容器 -d后台启动,-p映射容器2181端口到宿主机2181端口,限制容器最大内存占用为128m,–restart容器自动重启 docker run -d -p 2181:2181 -m 128m --restartalways --name zookeepe…...
Ubuntu 磁盘扩容
1.下载工具 sudo apt-get install gparted 2.调整大小...
如何在QGC中接收和处理无人机上传的各种传感器数据(如GPS、IMU等)。
在 QGroundControl (QGC) 中接收和处理无人机上传的各种传感器数据(如 GPS、IMU 等),主要通过 MAVLink 协议实现。MAVLink 是一种轻量级的消息传输协议,用于无人机和地面站之间的通信。QGC 通过 MAVLink 消息接收来自无人机的传感…...
Spring配置Bean自己的关系:继承和依赖
继承:这里的继承不是Java中类之间的继承, 是指配置文件中Bean配置项之间的继承。 用parent属性,配置要继承的bean,这样可以把相同的部分去去掉,下上两个bean的关系就变成了父bean和子bean, 子bean可以继承父…...
科技与狠活
科技与狠货,已经见怪不怪了 从黑龙江到海南,从上海到新疆,960万平方公里,十三亿人,每个地方都是科技与狠活 在抖音上面看到一个评论,如果蔬菜没科技与狠活,估计会很贵,但是我想到在…...
Vue:axios请求数据转存leanCloud
思路: 采用axios请求需要的数据,查看leanCloud中数据批量存储的格式,将两个数据进行对比,将请求得到的数据封装为云服务存储的格式,再发leanCloud存储数据的请求完成转存 1.封装js代码 //批量操作新增数据 import r…...
实战篇(九):解锁3D魔方的秘密:用Processing编程实现交互式魔方
解锁3D魔方的秘密:用Processing编程实现交互式魔方 使用 Processing 创建一个 3D 魔方效果展示1. 安装 Processing2. 项目结构3. 代码实现4. 代码解释4.1. 初始化魔方4.2. 绘制魔方4.3. 处理鼠标事件4.4. 检查点击的面4.5. 旋转面和最终确定旋转5. 运行和测试6. 细节解释6.1. …...
Android系统上常见的性能优化工具
Android系统上常见的性能优化工具 在Android系统开发中,性能优化是一个重要的任务,有许多工具可以帮助你进行各种方面的性能分析和优化。以下是一些常见的Android性能优化工具及其用途和使用方法: 1. Android Studio Profiler 功能: 提供CP…...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...
Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
【生成模型】视频生成论文调研
工作清单 上游应用方向:控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...
