当前位置: 首页 > news >正文

常见锁类型介绍

下面结合代码详细介绍 MutexRW LockFutex自旋锁信号量条件变量 和 synchronized,并分析它们的适用场景、特点以及为什么这些锁适用于特定场景。我们将从锁的实现机制和性能特点出发,解释其适用性。


1. Mutex(互斥锁)

代码示例

#include <iostream>
#include <thread>
#include <mutex>std::mutex mtx; // 定义一个互斥锁
int shared_data = 0;void increment() {for (int i = 0; i < 100000; ++i) {mtx.lock();   // 加锁++shared_data; // 访问共享资源mtx.unlock(); // 解锁}
}int main() {std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();std::cout << "Final value of shared_data: " << shared_data << std::endl;return 0;
}

特点

  • 独占访问:同一时间只有一个线程可以持有锁。

  • 阻塞等待:如果锁被占用,请求锁的线程会被阻塞,直到锁被释放。

  • 不可重入:标准 mutex 不可重入,但可以通过递归 mutex 实现重入。

适用场景

  • 保护临界区:确保同一时间只有一个线程访问共享资源。

  • 锁持有时间较长:适用于锁持有时间较长的场景,因为阻塞等待不会浪费 CPU 资源。

为什么适用

  • 实现机制:Mutex 通过操作系统提供的阻塞机制(如 futex)实现,线程在锁被占用时会进入睡眠状态,不会占用 CPU。

  • 性能特点:适合锁持有时间较长的场景,因为线程睡眠不会浪费 CPU 资源。


2. RW Lock(读写锁)

代码示例

#include <iostream>
#include <thread>
#include <shared_mutex>std::shared_mutex rw_mtx; // 定义一个读写锁
int shared_data = 0;void reader(int id) {for (int i = 0; i < 5; ++i) {rw_mtx.lock_shared(); // 加读锁std::cout << "Reader " << id << " read: " << shared_data << std::endl;rw_mtx.unlock_shared(); // 解读锁std::this_thread::sleep_for(std::chrono::milliseconds(100));}
}void writer(int id) {for (int i = 0; i < 5; ++i) {rw_mtx.lock(); // 加写锁++shared_data;std::cout << "Writer " << id << " wrote: " << shared_data << std::endl;rw_mtx.unlock(); // 解写锁std::this_thread::sleep_for(std::chrono::milliseconds(100));}
}int main() {std::thread readers[3];std::thread writers[2];for (int i = 0; i < 3; ++i) readers[i] = std::thread(reader, i);for (int i = 0; i < 2; ++i) writers[i] = std::thread(writer, i);for (int i = 0; i < 3; ++i) readers[i].join();for (int i = 0; i < 2; ++i) writers[i].join();return 0;
}

特点

  • 读共享:多个读线程可以同时持有读锁。

  • 写独占:写锁是独占的,写线程持有锁时,其他线程不能获取读锁或写锁。

适用场景

  • 读多写少:适用于读操作远多于写操作的场景,如缓存系统、数据库。

  • 读操作不修改共享资源:读操作不会修改共享资源,因此可以并发执行。

为什么适用

  • 实现机制:读写锁通过计数器跟踪读锁的数量,写锁需要等待所有读锁释放。

  • 性能特点:在读多写少的场景中,读写锁可以显著提高并发性能。


3. 自旋锁(Spinlock)

代码示例

#include <iostream>
#include <thread>
#include <atomic>std::atomic_flag spinlock = ATOMIC_FLAG_INIT; // 定义一个自旋锁
int shared_data = 0;void increment() {for (int i = 0; i < 100000; ++i) {while (spinlock.test_and_set(std::memory_order_acquire)); // 自旋等待++shared_data; // 访问共享资源spinlock.clear(std::memory_order_release); // 释放锁}
}int main() {std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();std::cout << "Final value of shared_data: " << shared_data << std::endl;return 0;
}

特点

  • 忙等待:线程不会进入睡眠状态,而是不断检查锁的状态。

  • 低延迟:适用于锁持有时间非常短的场景,避免了线程切换的开销。

  • 高 CPU 占用:如果锁持有时间较长,会导致 CPU 资源的浪费。

适用场景

  • 锁持有时间非常短:适用于锁持有时间非常短的场景,如内核中的中断处理程序。

  • 多核处理器上的高并发场景:在多核处理器上,自旋锁可以避免线程切换的开销。

为什么适用

  • 实现机制:自旋锁通过忙等待实现,不会让线程进入睡眠状态。

  • 性能特点:适合锁持有时间非常短的场景,因为忙等待的代价低于线程切换的开销。


4. 信号量(Semaphore)

代码示例

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>class Semaphore {
public:Semaphore(int count = 0) : count(count) {}void acquire() {std::unique_lock<std::mutex> lock(mtx);cv.wait(lock, [this]{ return count > 0; });--count;}void release() {std::lock_guard<std::mutex> lock(mtx);++count;cv.notify_one();}private:std::mutex mtx;std::condition_variable cv;int count;
};Semaphore sem(2); // 初始化信号量,允许 2 个线程同时访问void task(int id) {sem.acquire();std::cout << "Task " << id << " is running!" << std::endl;std::this_thread::sleep_for(std::chrono::seconds(1));sem.release();
}int main() {std::thread t1(task, 1);std::thread t2(task, 2);std::thread t3(task, 3);t1.join();t2.join();t3.join();return 0;
}

特点

  • 计数机制:信号量维护一个计数器,用于控制对共享资源的访问数量。

  • 阻塞等待:如果计数器为 0,线程会阻塞等待。

适用场景

  • 限制并发访问数量:适用于资源池管理(如线程池、连接池)。

  • 生产者-消费者模型:用于控制生产者和消费者的并发数量。

为什么适用

  • 实现机制:信号量通过计数器和条件变量实现,可以灵活控制并发访问数量。

  • 性能特点:适合需要限制并发访问数量的场景。


5. 条件变量(Condition Variable)

代码示例

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>std::mutex mtx;
std::condition_variable cv;
bool ready = false;void worker() {std::unique_lock<std::mutex> lock(mtx);cv.wait(lock, []{ return ready; }); // 等待条件满足std::cout << "Worker is running!" << std::endl;
}int main() {std::thread t(worker);std::this_thread::sleep_for(std::chrono::seconds(2));{std::lock_guard<std::mutex> lock(mtx);ready = true;}cv.notify_one(); // 通知等待的线程t.join();return 0;
}

特点

  • 条件同步:用于线程间的条件同步。

  • 阻塞等待:线程会阻塞等待条件满足。

适用场景

  • 复杂的同步需求:如生产者-消费者模型。

  • 线程间协作:适用于需要线程间协作的场景。

为什么适用

  • 实现机制:条件变量通过阻塞和唤醒机制实现线程间同步。

  • 性能特点:适合需要复杂同步的场景。


6. synchronized(Java 中的锁机制)

代码示例

public class Counter {private int count = 0;public synchronized void increment() {count++;}public int getCount() {return count;}public static void main(String[] args) throws InterruptedException {Counter counter = new Counter();Thread t1 = new Thread(() -> {for (int i = 0; i < 100000; i++) {counter.increment();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 100000; i++) {counter.increment();}});t1.start();t2.start();t1.join();t2.join();System.out.println("Final count: " + counter.getCount());}
}

特点

  • 内置锁:Java 中的 synchronized 关键字提供了一种简单的锁机制。

  • 可重入:同一个线程可以多次获取锁。

适用场景

  • 简单的同步需求:适用于不需要复杂锁机制的场景。

  • 单线程重入:适用于需要重入锁的场景。

为什么适用

  • 实现机制synchronized 通过 JVM 内置的锁机制实现,简单易用。

  • 性能特点:适合简单的同步需求。


总结

锁类型特点适用场景为什么适用
Mutex独占访问,阻塞等待保护临界区,锁持有时间较长的场景通过阻塞机制实现,适合锁持有时间较长的场景
RW Lock读共享,写独占读多写少的场景,如缓存系统、数据库通过计数器实现读共享,适合读多写少的场景
自旋锁忙等待,不阻塞线程锁持有时间非常短的场景,多核处理器上的高并发场景通过忙等待实现,适合锁持有时间非常短的场景
信号量控制对共享资源的访问数量资源池管理,限制同时访问共享资源的线程数量通过计数器和条件变量实现,适合需要限制并发访问数量的场景
条件变量线程间条件同步复杂的同步需求,如生产者-消费者模型通过阻塞和唤醒机制实现,适合需要复杂同步的场景
synchronized内置锁,简单易用简单的同步需求,单线程重入通过 JVM 内置锁机制实现,适合简单的同步需求

通过代码示例和实现机制的分析,可以更好地理解各种锁的适用场景和性能特点。选择合适的锁类型取决于具体的应用场景和性能需求。

相关文章:

常见锁类型介绍

下面结合代码详细介绍 Mutex、RW Lock、Futex、自旋锁、信号量、条件变量 和 synchronized&#xff0c;并分析它们的适用场景、特点以及为什么这些锁适用于特定场景。我们将从锁的实现机制和性能特点出发&#xff0c;解释其适用性。 1. Mutex&#xff08;互斥锁&#xff09; 代…...

Java中,Scanner和System.out超时的解决方法及原理

ACM 模式的原理 在输入输出的时候&#xff0c;会先将输入输出的东西放在一个文件里&#xff0c;这个文件也叫做 IO 设备 为什么 Scanner 会慢 new 一个 Scanner &#xff0c;在 Scanner 里面调用 next 的时候&#xff0c;程序会直接访问 IO 设备。在调用一个 next 的时候&…...

一种数据高效具身操作的原子技能库构建方法

25年1月来自京东、中科大、深圳大学、海尔集团、地平线机器人和睿尔曼智能科技的论文“An Atomic Skill Library Construction Method for Data-Efficient Embodied Manipulation”。 具身操控是具身人工智能领域的一项基本能力。尽管目前的具身操控模型在特定场景下表现出一定…...

云创智城YunCharge 新能源二轮、四轮充电解决方案(云快充、万马爱充、中电联、OCPP1.6J等多个私有单车、汽车充电协议)之新能源充电行业系统说明书

云创智城YunCharge 新能源充电行业系统说明书 ⚡官方文档 ⚡官网地址 1. 引言 随着全球环境保护和能源危机的加剧&#xff0c;新能源汽车行业得到了快速发展&#xff0c;充电基础设施建设也随之蓬勃发展。新能源充电行业系统旨在提供高效、便捷的充电服务&#xff0c;满足电…...

JVM垃圾回收器深度底层原理分析与知识体系构建

一、垃圾回收的基本步骤 标记&#xff08;Marking&#xff09; 从GC Roots&#xff08;如虚拟机栈、方法区静态变量、本地方法栈等&#xff09;出发&#xff0c;遍历对象引用链&#xff0c;标记所有可达对象为存活对象&#xff0c;未被标记的则视为垃圾。此阶段需暂停用户线程&…...

30.[前端开发-JavaScript基础]Day07-数组Array-高阶函数-日期Date-DOM

JavaScript的DOM操作 &#xff08;一&#xff09; 1 什么是DOM&#xff1f; 认识DOM和BOM 深入理解DOM 2 认识DOM Tree DOM Tree的理解 3 DOM的整体结构 DOM的学习顺序 DOM的继承关系图 document对象 4 节点、元素导航 节点&#xff08;Node&#xff09;之间的导航&…...

IP、网关、子网掩码、DNS 之间的关系详解

IP、网关、子网掩码、DNS 之间的关系详解 在计算机网络中&#xff0c;IP、网关、子网掩码和 DNS 是几个关键概念&#xff0c;它们协同工作&#xff0c;共同保障网络通信的顺畅。本文将详细探讨它们之间的关系。 一、IP 地址 IP 地址是网络中设备的唯一标识&#xff0c;如同现…...

【Day50 LeetCode】图论问题 Ⅷ

一、图论问题 Ⅷ 1、dijkstra算法 堆优化 采用堆来优化&#xff0c;适合节点多的稀疏图。代码如下&#xff1a; # include<iostream> # include<vector> # include<list> # include<queue> # include<climits>using namespace std;class myco…...

结构体介绍及内存大小分配问题

结构体 一.结构体的介绍1.1结构体的声明1.2匿名结构体1.3结构的自引用1.4使用 typedef 简化结构体类型名 二.结构体内存对齐2.1内存对齐规则2.2结构体内存对齐原因2.3修改默认对齐数 在 C 语言中&#xff0c;结构体&#xff08;struct&#xff09;是一种用户自定义的数据类型&a…...

halcon 条形码、二维码识别、opencv识别

一、条形码 函数介绍 create_bar_code_model * 1.创建条码读取器的模板 * 参数一&#xff1a;通用参数的名称&#xff0c;针对条形码模型进行调整。默认值为空 * 参数二&#xff1a;针对条形码模型进行调整 * 参数三&#xff1a;条形码模型的句柄。 create_bar_code_model (…...

Vue框架的使用 搭建打包 Vue的安全问题(Xss,源码泄露)

前言 什么是Vue&#xff1f; Vue是轻量级的js框架 可以帮助我们一键构造网站&#xff0c;打包app程序等 Vue的基本使用 1、构造框架并启用 新建一个 目录 使用终端切换到当前的目录 创建vue项目 第一个弹出使用语法我们选择是 剩下的全选择否 发现创建好了 接着进行…...

Java+SpringBoot+Vue+数据可视化的音乐推荐与可视化平台(程序+论文+讲解+安装+调试+售后)

感兴趣的可以先收藏起来&#xff0c;还有大家在毕设选题&#xff0c;项目以及论文编写等相关问题都可以给我留言咨询&#xff0c;我会一一回复&#xff0c;希望帮助更多的人。 系统介绍 在互联网技术以日新月异之势迅猛发展的浪潮下&#xff0c;5G 通信技术的普及、云计算能力…...

day2 - SpringBoot框架开发技术

主要内容 1. SpringBoot简介 2. 构建springboot工程 3. springboot接口返回json 4. springboot热部署 5. springboot资源属性配置 6. springboot整合模板引擎 7. springboot异常处理 8. springboot整合MyBatis 9. springboot整合redis 10. springboot整合定时任务 11. springbo…...

Flash-03

1-问题&#xff1a;Flash软件画两个图形&#xff0c;若有部分重合则变为一个整体 解决方法1&#xff1a;两个图形分属于不同的图层 解决方法2&#xff1a;将每个图形都转化为【元件】 问题2&#xff1a;元件是什么&#xff1f; 在 Adobe Flash&#xff08;现在称为 Adobe Anim…...

新建菜单项的创建之CmpGetValueListFromCache函数分析

第一部分&#xff1a; PCELL_DATA CmpGetValueListFromCache( IN PHHIVE Hive, IN PCACHED_CHILD_LIST ChildList, OUT BOOLEAN *IndexCached, OUT PHCELL_INDEX ValueListToRelease ) 0: kd> dv KeyControlBlock 0xe1…...

【Word2Vec】Skip-gram 的直观理解(深入浅出)

01 什么是skip-gram 一句话来说就是&#xff0c;给定中心词&#xff0c;然后预测其周围的词&#xff1a; 02 模型结构 对于skip-gram来说&#xff0c;输入是一个[1 x V]维的ont-hot向量&#xff0c;其中V为词表大小&#xff0c;值为1的那一项就表示我们的中心词。经过一个[V x…...

在MacOS上打造本地部署的大模型知识库(一)

一、在MacOS上安装Ollama docker run -d -p 3000:8080 --add-hosthost.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main 最后停掉Docker的ollama&#xff0c;就能在webui中加载llama模…...

(21)从strerror到strtok:解码C语言字符函数的“生存指南2”

❤个人主页&#xff1a;折枝寄北的博客 ❤专栏位置&#xff1a;简单入手C语言专栏 目录 前言1. 错误信息报告1.1 strerror 2. 字符操作2.1 字符分类函数2.2 字符转换函数 3. 内存操作函数3.1 memcpy3.2 memmove3.2memset3.3 memcmp 感谢您的阅读 前言 当你写下strcpy(dest, s…...

DeepSeek推出DeepEP:首个开源EP通信库,让MoE模型训练与推理起飞!

今天&#xff0c;DeepSeek 在继 FlashMLA 之后&#xff0c;推出了第二个 OpenSourceWeek 开源项目——DeepEP。 作为首个专为MoE&#xff08;Mixture-of-Experts&#xff09;训练与推理设计的开源 EP 通信库&#xff0c;DeepEP 在EP&#xff08;Expert Parallelism&#xff09…...

1.2 Kaggle大白话:Eedi竞赛Transformer框架解决方案02-GPT_4o生成训练集缺失数据

目录 0. 本栏目竞赛汇总表1. 本文主旨2. AI工程架构3. 数据预处理模块3.1 配置数据路径和处理参数3.2 配置API参数3.3 配置输出路径 4. AI并行处理模块4.1 定义LLM客户端类4.2 定义数据处理函数4.3 定义JSON保存函数4.4 定义数据分片函数4.5 定义分片处理函数4.5 定义文件名排序…...

3个关键功能解析:USBToolBox如何简化macOS与Windows的USB端口映射难题

3个关键功能解析&#xff1a;USBToolBox如何简化macOS与Windows的USB端口映射难题 【免费下载链接】tool the USBToolBox tool 项目地址: https://gitcode.com/gh_mirrors/too/tool 在Hackintosh和跨平台开发领域&#xff0c;USB端口映射一直是个令人头疼的技术难题。US…...

Kerberos身份认证原理与实战排错指南

1. 为什么今天还要花时间搞懂 Kerberos&#xff1f;——一个被低估的“老协议”正在悄悄支撑着你的日常你每天登录公司内网查邮件、访问财务系统提交报销、用 Jenkins 构建代码、甚至在 Windows 域环境中打开一台同事的共享文件夹……这些看似顺滑的操作背后&#xff0c;大概率…...

Hitboxer:开源SOCD清理工具,3分钟提升游戏操作精准度

Hitboxer&#xff1a;开源SOCD清理工具&#xff0c;3分钟提升游戏操作精准度 【免费下载链接】socd Key remapper for epic gamers 项目地址: https://gitcode.com/gh_mirrors/so/socd 你是否在激烈的游戏对抗中经历过这样的挫败&#xff1a;同时按下左右方向键时角色卡…...

Yokogawa AAI835-H50/K4A00模拟输入/输出模块

Yokogawa AAI835-H50/K4A00 模拟输入/输出模块产品特点&#xff1a;通道配置&#xff1a;共8个通道&#xff0c;含4路模拟输入和4路模拟输出。信号类型&#xff1a;所有通道均支持4-20mA标准电流信号。HART通信&#xff1a;支持HART协议&#xff0c;可与智能现场设备双向数字通…...

Java数组工具类实战:设计不可实例化的静态工具类

实现一个工具类 MathUtils&#xff0c;满足以下要求&#xff1a; 1. 所有方法均为静态&#xff0c;且该类不能从外部实例化&#xff08;提示&#xff1a;使用私有构造器&#xff09;。 2. 提供三个静态方法&#xff1a;- maxArray(int[] arr)&#xff1a;返回较大值&#xff1b…...

组态王通用扫码枪配置

使用组态王扫码枪驱动&#xff0c;是绑定变量&#xff0c;扫码后直接就可以显示扫码内容。解决每次扫码输入数据时必须先用鼠标点进输入框内的问题。驱动安装先添加驱动&#xff0c;亚控网站的文件为 barcodescanner&#xff0c;这个文件是组态王通用扫码枪的驱动&#xff0c;但…...

2026年LLM推理加速全景:量化、投机解码与KV Cache工程实战

大语言模型推理速度慢、成本高&#xff0c;是阻碍AI大规模落地的核心障碍之一。一个7B参数的模型&#xff0c;在标准配置下每秒只能生成约30个token&#xff0c;对于需要实时响应的应用来说几乎无法接受。但2026年&#xff0c;一系列推理加速技术的成熟&#xff0c;让这一局面发…...

操作符从浅入深的讲解

1. 操作符的分类 2. ⼆进制和进制转换 3. 原码、反码、补码 4. 移位操作符 5. 位操作符&#xff1a;&、|、^、~ 6. 单⽬操作符 7. 逗号表达式 8. 下标访问[]、函数调⽤() 9. 结构成员访问操作符 10. 操作符的属性&#xff1a;优先级、结合性 11. 表达式求值1.操作符的分类以…...

PS5 NOR Modifier深度解析:如何通过Windows工具修复PS5硬件故障与实现光驱版转数字版

PS5 NOR Modifier深度解析&#xff1a;如何通过Windows工具修复PS5硬件故障与实现光驱版转数字版 【免费下载链接】PS5NorModifier The PS5 Nor Modifier is an easy to use Windows based application to rewrite your PS5 NOR file. This can be useful if your NOR is corru…...

哪款台灯护眼效果最好孩子用?实测口碑爆款护眼灯品牌,买前必看

哪款台灯护眼效果最好孩子用&#xff1f;作为家长&#xff0c;最揪心的就是孩子的视力问题。有数据显示&#xff0c;现在孩子近视率越来越高&#xff0c;小学就有不少戴眼镜的&#xff0c;中学更是过半&#xff0c;看着实在让人担心。 孩子每天低头写作业、看书&#xff0c;灯光…...