C++多线程编程中的锁详解
在现代软件开发中,多线程编程是提升应用程序性能和响应能力的重要手段。然而,多线程编程也带来了数据竞争和死锁等复杂问题。为了确保线程间的同步和共享数据的一致性,C++标准库提供了多种锁机制。
1. std::mutex
std::mutex
是最基础的互斥锁,用于保护共享数据,防止多个线程同时访问该数据。
#include <iostream>
#include <thread>
#include <mutex>std::mutex mtx;void print_thread_id(int id) {mtx.lock();std::cout << "Thread " << id << std::endl;mtx.unlock();
}int main() {std::thread t1(print_thread_id, 1);std::thread t2(print_thread_id, 2);t1.join();t2.join();return 0;
}
在上述代码中,mtx.lock()
和mtx.unlock()
分别用于加锁和解锁,确保同一时刻只有一个线程可以访问临界区(std::cout
操作)。
2. std::recursive_mutex
std::recursive_mutex
允许同一线程多次获得同一锁,而不会导致死锁。适用于递归调用中需要加锁的场景。
#include <iostream>
#include <thread>
#include <mutex>std::recursive_mutex rec_mtx;void recursive_function(int count) {if (count <= 0) return;rec_mtx.lock();std::cout << "Count: " << count << std::endl;recursive_function(count - 1);rec_mtx.unlock();
}int main() {std::thread t(recursive_function, 5);t.join();return 0;
}
3. std::timed_mutex
std::timed_mutex
支持尝试在一定时间内获取锁。这在避免死锁和提高程序响应性方面很有用。
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>std::timed_mutex tmtx;void try_lock_for_example() {if (tmtx.try_lock_for(std::chrono::seconds(1))) {std::cout << "Lock acquired" << std::endl;std::this_thread::sleep_for(std::chrono::seconds(2));tmtx.unlock();} else {std::cout << "Failed to acquire lock" << std::endl;}
}int main() {std::thread t1(try_lock_for_example);std::thread t2(try_lock_for_example);t1.join();t2.join();return 0;
}
4. std::recursive_timed_mutex
std::recursive_timed_mutex
结合了std::recursive_mutex
和std::timed_mutex
的特性
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>std::recursive_timed_mutex rtmtx;void recursive_timed_function(int count) {if (count <= 0) return;if (rtmtx.try_lock_for(std::chrono::seconds(1))) {std::cout << "Count: " << count << std::endl;recursive_timed_function(count - 1);rtmtx.unlock();} else {std::cout << "Failed to acquire lock" << std::endl;}
}int main() {std::thread t(recursive_timed_function, 5);t.join();return 0;
}
5. std::shared_mutex
(C++17引入)
std::shared_mutex
允许多个线程同时读取共享数据,但只允许一个线程写入数据。这种机制适用于读多写少的场景。
#include <iostream>
#include <thread>
#include <shared_mutex>std::shared_mutex smtx;void read_function() {smtx.lock_shared();std::cout << "Reading data" << std::endl;smtx.unlock_shared();
}void write_function() {smtx.lock();std::cout << "Writing data" << std::endl;smtx.unlock();
}int main() {std::thread t1(read_function);std::thread t2(read_function);std::thread t3(write_function);t1.join();t2.join();t3.join();return 0;
}
6. std::shared_timed_mutex
(C++14引入)
std::shared_timed_mutex
结合了std::shared_mutex
和std::timed_mutex
的特性。
#include <iostream>
#include <thread>
#include <shared_mutex>
#include <chrono>std::shared_timed_mutex stmtx;void shared_timed_read_function() {if (stmtx.try_lock_shared_for(std::chrono::seconds(1))) {std::cout << "Reading data" << std::endl;std::this_thread::sleep_for(std::chrono::seconds(2));stmtx.unlock_shared();} else {std::cout << "Failed to acquire shared lock" << std::endl;}
}void shared_timed_write_function() {if (stmtx.try_lock_for(std::chrono::seconds(1))) {std::cout << "Writing data" << std::endl;std::this_thread::sleep_for(std::chrono::seconds(2));stmtx.unlock();} else {std::cout << "Failed to acquire exclusive lock" << std::endl;}
}int main() {std::thread t1(shared_timed_read_function);std::thread t2(shared_timed_read_function);std::thread t3(shared_timed_write_function);t1.join();t2.join();t3.join();return 0;
}
7. std::lock_guard
std::lock_guard
提供一种异常安全的方式来管理锁的生命周期,通常用于自动解锁。
#include <iostream>
#include <thread>
#include <mutex>std::mutex mtx;void lock_guard_example() {std::lock_guard<std::mutex> lock(mtx);std::cout << "Lock acquired using lock_guard" << std::endl;// mtx is automatically unlocked when lock goes out of scope
}int main() {std::thread t(lock_guard_example);t.join();return 0;
}
8. std::unique_lock
std::unique_lock
比std::lock_guard
更加灵活,支持延迟加锁、解锁和重新加锁。
#include <iostream>
#include <thread>
#include <mutex>std::mutex mtx;void unique_lock_example() {std::unique_lock<std::mutex> lock(mtx);std::cout << "Lock acquired using unique_lock" << std::endl;lock.unlock();std::cout << "Lock released" << std::endl;lock.lock();std::cout << "Lock reacquired" << std::endl;
}int main() {std::thread t(unique_lock_example);t.join();return 0;
}
9. std::shared_lock
(C++17引入)
std::shared_lock
用于管理共享互斥量(std::shared_mutex
或std::shared_timed_mutex
),提供了一种简单的方式来处理读锁。
#include <iostream>
#include <thread>
#include <shared_mutex>std::shared_mutex smtx;void shared_lock_example() {std::shared_lock<std::shared_mutex> lock(smtx);std::cout << "Shared lock acquired" << std::endl;
}int main() {std::thread t1(shared_lock_example);std::thread t2(shared_lock_example);t1.join();t2.join();return 0;
}
结论
C++标准库提供了多种锁机制,帮助开发者在多线程环境中确保数据的一致性和线程的同步。根据具体的应用场景选择合适的锁,可以有效地避免数据竞争和死锁问题,从而编写出高效、安全的多线程程序。
相关文章:
C++多线程编程中的锁详解
在现代软件开发中,多线程编程是提升应用程序性能和响应能力的重要手段。然而,多线程编程也带来了数据竞争和死锁等复杂问题。为了确保线程间的同步和共享数据的一致性,C标准库提供了多种锁机制。 1. std::mutex std::mutex是最基础的互斥锁…...

van-dialog 组件调用报错
报错截图 报错原因 这个警告表明 vue 在渲染页面时遇到了一个未知的自定义组件 <van-dialog>,并且提示可能是由于未正确注册该组件导致的。在 vue 中,当我们使用自定义组件时,需要先在 vue 实例中注册这些组件,以便 vue 能…...

【Django】在vscode中运行调试Django项目(命令及图形方式)
文章目录 命令方式图形方式默认8000端口设置自定义端口 命令方式 python manage.py runserver图形方式 默认8000端口 设置自定义端口...
麦田物语第十三天
系列文章目录 麦田物语第十三天 文章目录 系列文章目录一、实现根据物品详情显示 ItemTooltip1.ItemTooltips脚本编写二、制作 Player 的动画一、实现根据物品详情显示 ItemTooltip 1.ItemTooltips脚本编写 首先创建Scripts->Inventory->UI->ItemTooltip脚本,然后…...

【Git多人协作开发】不同的分支下的多人协作开发模式
目录 0.前言背景 1.开发者1☞完成准备工作&协作开发 1.1查看分支情况 1.2创建本地分支feature-1 1.3三板斧 1.4push推本地分支feature-1到远程仓库 2.开发者2☞完成准备工作&协作开发 2.1创建本地分支feature-2 2.2三板斧 2.2push推送本地feature-2到远程仓库…...
Lua 复数计算器
Lua复数计算器 主要包括复数的加减乘除操作,以及打印 编写复数类 -- ***** 元类 ***** Complex {real 0, imag 0}-- 构造函数 function Complex:new(real, imag)local o o or {}o.real real or 0o.imag imag or 0setmetatable(o, self)self.__index selfr…...
深入MySQL中的IF和IFNULL函数
在数据库查询中,我们经常需要根据条件来决定数据的显示方式。MySQL提供了多种内置函数来帮助我们实现这种条件逻辑,其中IF和IFNULL是两个非常有用的函数。在这篇博客中,我们将深入探讨这两个函数的用法和它们在实际查询中的应用。 IF函数 I…...

AI多模态实战教程:面壁智能MiniCPM-V多模态大模型问答交互、llama.cpp模型量化和推理
一、项目简介 MiniCPM-V 系列是专为视觉-语⾔理解设计的多模态⼤型语⾔模型(MLLMs),提供⾼质量的⽂本输出,已发布4个版本。 1.1 主要模型及特性 (1)MiniCPM-Llama3-V 2.5: 参数规模: 8B性能…...

Docker 搭建Elasticsearch详细步骤
本章教程使用Docker搭建Elasticsearch环境。 一、拉取镜像 docker pull docker.elastic.co/elasticsearch/elasticsearch:8.8.2二、运行容器 docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-n...
mysql中提供的函数
文章目录 1.聚合函数2.字符串函数3.数值函数4.日期函数5.流程函数 MySQL 是一个功能强大的关系型数据库管理系统,其中包含了丰富的内置函数,用于处理各种数据操作和查询。这些函数可以分为多种类型,包括字符串函数、数值函数、日期和时间函数…...

加速下载,揭秘Internet Download Manager2024下载器的威力!
1. Internet Download Manager(IDM)是一款广受欢迎的下载管理软件,以其强大的下载加速功能和用户友好的界面著称。 IDM马丁正版下载如下: https://wm.makeding.com/iclk/?zoneid34275 idm最新绿色版一键安装包链接:抓紧保存以…...
oracle 宽表设计
Oracle宽表设计主要涉及到数据库表或视图中字段(列)数量较多的情况。在Oracle 23c及以后的版本中,数据库表或视图中允许的最大列数已增加到4096,这为宽表设计提供了更大的灵活性。以下是对Oracle宽表设计的详细分析: …...

winrar安装好后,鼠标右键没有弹出解压的选项
本来安装挺好的,可以正常使用,有天我把winrar相关的文件挪了个位置,就不能正常使用了。 然后我去应用里面找,找到应用标识了,但是找不到对应的文件夹(因为我挪到另外一个文件夹里了)。 于是我找…...

数字图像处理笔记(一)---- 图像数字化与显示
系列文章目录 数字图像处理学习笔记(一)---- 图像数字化与显示 数字图像处理笔记(二)---- 像素加图像统计特征 数字图像处理笔记(三) ---- 傅里叶变换的基本原理 文章目录 系列文章目录前言一、数字图像处理二、图像数…...

Unity UGUI 之 事件接口
本文仅作学习笔记与交流,不作任何商业用途 本文包括但不限于unity官方手册,唐老狮,麦扣教程知识,引用会标记,如有不足还请斧正 本文在发布时间选用unity 2022.3.8稳定版本,请注意分别 1.什么是事件接口&…...

Hadoop、HDFS、MapReduce 大数据解决方案
本心、输入输出、结果 文章目录 Hadoop、HDFS、MapReduce 大数据解决方案前言HadoopHadoop 主要组件的Web UI端口和一些基本信息MapReduceMapReduce的核心思想MapReduce的工作流程MapReduce的优缺点Hadoop、HDFS、MapReduce 大数据解决方案 编辑 | 简简单单 Online zuozuo 地址…...
Dubbo SPI 之负载均衡
1. 背景介绍 在分布式系统中,负载均衡是一项核心技术,旨在将请求合理地分配到多个服务实例上,以提高系统的性能和可靠性。Dubbo 作为一个高性能的 Java RPC 框架,提供了多种负载均衡策略来满足不同的业务需求。本文将深入探讨 Du…...

规范:前后端接口规范
1、前言 随着互联网的高速发展,前端页面的展示、交互体验越来越灵活、炫丽,响应体验也要求越来越高,后端服务的高并发、高可用、高性能、高扩展等特性的要求也愈加苛刻,从而导致前后端研发各自专注于自己擅长的领域深耕细作。 然…...
Python --NumPy库基础方法(2)
NumPy Numpy(Numerical Python) 是科学计算基础库,提供大量科学计算相关功能,比如数据统计,随机数生成等。其提供最核心类型为多维数组类型(ndarray),支持大量的维度数组与矩阵运算,Numpy支持向…...
音视频入门基础:H.264专题(15)——FFmpeg源码中通过SPS属性获取视频帧率的实现
音视频入门基础:H.264专题系列文章: 音视频入门基础:H.264专题(1)——H.264官方文档下载 音视频入门基础:H.264专题(2)——使用FFmpeg命令生成H.264裸流文件 音视频入门基础&…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...

英国云服务器上安装宝塔面板(BT Panel)
在英国云服务器上安装宝塔面板(BT Panel) 是完全可行的,尤其适合需要远程管理Linux服务器、快速部署网站、数据库、FTP、SSL证书等服务的用户。宝塔面板以其可视化操作界面和强大的功能广受国内用户欢迎,虽然官方主要面向中国大陆…...
Spring事务传播机制有哪些?
导语: Spring事务传播机制是后端面试中的必考知识点,特别容易出现在“项目细节挖掘”阶段。面试官通过它来判断你是否真正理解事务控制的本质与异常传播机制。本文将从实战与源码角度出发,全面剖析Spring事务传播机制,帮助你答得有…...
2025年全国I卷数学压轴题解答
第19题第3问: b b b 使得存在 t t t, 对于任意的 x x x, 5 cos x − cos ( 5 x t ) < b 5\cos x-\cos(5xt)<b 5cosx−cos(5xt)<b, 求 b b b 的最小值. 解: b b b 的最小值 b m i n min t max x g ( x , t ) b_{min}\min_{t} \max_{x} g(x,t) bmi…...

python3GUI--基于PyQt5+DeepSort+YOLOv8智能人员入侵检测系统(详细图文介绍)
文章目录 一.前言二.技术介绍1.PyQt52.DeepSort3.卡尔曼滤波4.YOLOv85.SQLite36.多线程7.入侵人员检测8.ROI区域 三.核心功能1.登录注册1.登录2.注册 2.主界面1.主界面简介2.数据输入3.参数配置4.告警配置5.操作控制台6.核心内容显示区域7.检…...

MTK-Android12-13 Camera2 设置默认视频画质功能实现
MTK-Android12-13 Camera2 设置默认视频画质功能实现 场景:部分客户使用自己的mipi相机安装到我们主板上,最大分辨率为1280720,但是视频画质默认的是640480。实际场景中,在默认视频分辨率情况下拍出来的视频比较模糊、预览也不清晰…...

KKCMS部署
目录 账号 网站目录 快看CMS使用手册 http://10.141.19.241/kkcms/install/ 常规思路:页面点点观察url变化,参数 常规思路:点一个功能模块抓包看什么东西,正确是什么样,错误的是什么样,构造参数。 账号…...