C++ 互斥锁的使用
mutex
std::mutex 是C++标准库中用于线程同步的互斥锁机制,主要用于保护共享资源,避免多个线程同时访问导致的竞态条件。
它提供了以下功能:
-
加锁(
lock):阻塞当前线程,直到获取锁。 -
解锁(
unlock):释放锁,允许其他线程获取锁。 -
尝试加锁(
try_lock):尝试获取锁,如果锁已被占用则立即返回。
使用全局锁案例
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
mutex mtx; // 定义一个全局互斥锁
int shared_data = 0;void increment() {for (int i = 0; i < 10000; i++) {mtx.lock(); // 加锁shared_data++;mtx.unlock(); // 解锁}
}int main() {thread t1(increment);thread t2(increment);t1.join();t2.join();cout << "共享数据: " << shared_data << endl; // 输出应该是20000return 0;
}
使用传参锁案例
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
int shared_data = 0;void increment(mutex& mtx) {for (int i = 0; i < 10000; i++) {mtx.lock(); // 加锁shared_data++;mtx.unlock(); // 解锁}
}int main() {mutex mtx; // 使用传参互斥锁thread t1(increment,ref(mtx));//需要使用 ref 包装锁,不然会报错thread t2(increment,ref(mtx));t1.join();t2.join();cout << "共享数据: " << shared_data << endl; // 输出应该是20000return 0;
} timed_mutex
std::timed_mutex 是C++11引入的一种互斥锁类型,用于多线程编程中控制对共享资源的并发访问。它提供了超时机制,允许线程在尝试获取锁时设置一个时间限制,从而避免无限等待锁释放,降低死锁风险。
-
try_lock_for(duration):尝试在指定的时间内获取锁,如果超时则返回false。 -
try_lock_until(time_point):尝试在指定的时间点之前获取锁,如果超时则返回false。
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
using namespace std;
timed_mutex mtx;void func(int id) {chrono::seconds timeout(3); // 设置超时时间为3秒if (mtx.try_lock_for(timeout)) {cout << "线程 " << id << " 成功获取锁,执行临界区代码..." << endl;this_thread::sleep_for(chrono::seconds(5)); // 模拟工作负载mtx.unlock();}else {cout << "线程 " << id << " 超时未能获取锁,继续执行其他任务..." << endl;}
}int main() {thread t1(func, 1);thread t2(func, 2);t1.join();t2.join();return 0;
} recursive_mutex
- 调⽤⽅线程在从它成功调⽤ lock 或 try_lock 开始的时期⾥占有 recursive_mutex。此时期之内,线程可以进⾏对 lock 或 try_lock 的附加调⽤。所有权的时期在线程进⾏匹配次数的 unlock 调⽤时结束。
- 线程占有 recursive_mutex 时,若其他所有线程试图要求 recursive_mutex 的所有权,则它们将阻塞(对于调⽤ lock)或收到 false 返回值(对于调⽤ try_lock)。
#include <iostream>
#include <mutex>
#include <thread>
using namespace std;
recursive_mutex rec_mutex;void recursiveFunction(int count) {if (count <= 0) return;rec_mutex.lock();cout << "Lock acquired. Count: " << count << endl;// 递归调用recursiveFunction(count - 1);rec_mutex.unlock();cout << "Lock released. Count: " << count << endl;
}int main() {thread t(recursiveFunction, 3);t.join();return 0;
} lock_guard
std::lock_guard 是 C++ 标准库中用于管理互斥锁的 RAII(Resource Acquisition Is Initialization,资源获取即初始化)工具。它通过构造函数自动获取互斥锁,并在析构函数中自动释放锁,从而确保互斥锁的正确管理,避免因忘记解锁而导致的死锁问题。
主要特性
-
自动管理锁:通过构造函数获取锁,析构函数释放锁,无需手动调用
lock()和unlock()。 -
防止死锁:确保即使在异常情况下也能正确释放锁。
-
不可移动和复制:std::lock_guard 不支持拷贝或移动构造,确保锁的唯一性。
构造函数
explicit lock_guard(MutexType& mutex, std::adopt_lock_t tag = std::defer_lock); -
MutexType& mutex:要管理的互斥锁对象,如mutex,timed_mutex,recersive_mutex。
-
std::adopt_lock_t tag:可选参数,表示当前线程已经持有锁,默认值是 std::defer_lock,表示 lock_guard 会在构造时自动尝试加锁。如果传入 std::adopt_lock,则表示当前线程已经通过其他方式(例如 std::lock 或手动调用 lock())持有锁,lock_guard 不会再次尝试加锁,而是直接接管锁的管理。
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
mutex mtx;
void print_block(int n, char c) {lock_guard<mutex> lock(mtx); // 默认加锁,无需手动解锁for (int i = 0; i < n; ++i) {cout << c;}cout << '\n';
}int main() {thread t1(print_block, 50, '*');thread t2(print_block, 50, '$');t1.join();t2.join();return 0;
} unique_lock
主要特性
-
延迟加锁:可以在构造时不立即加锁,而是通过显式调用
lock()或unlock()来控制锁的获取和释放。 -
支持条件变量:可以与
std::condition_variable配合使用,支持线程间的同步。 -
可选锁管理:可以选择是否持有锁,或者在构造时直接接管已持有的锁。
-
支持多种互斥锁类型:可以与
std::mutex、std::recursive_mutex、std::timed_mutex和std::shared_mutex配合使用。
构造函数
template <typename Mutex>
unique_lock() noexcept; // 默认构造,不绑定任何锁template <typename Mutex>
explicit unique_lock(Mutex& m, std::defer_lock_t); // 延迟加锁template <typename Mutex>
unique_lock(Mutex& m, std::try_to_lock_t); // 尝试加锁,失败时不阻塞template <typename Mutex>
unique_lock(Mutex& m, std::adopt_lock_t); // 假设已持有锁,不加锁template <typename Mutex>
unique_lock(Mutex& m); // 默认加锁template <typename Mutex>
unique_lock(Mutex& m, std::unique_lock<Mutex>&& other); // 移动构造 主要成员函数
-
lock():尝试加锁,如果锁已被占用则阻塞。 -
try_lock():尝试加锁,如果锁已被占用则立即返回false。 -
unlock():释放锁。 -
owns_lock():检查是否持有锁。 -
mutex():获取绑定的互斥锁对象。 -
release():释放锁的所有权,但不释放锁本身。 -
swap():交换两个std::unique_lock的状态。
lock和try_lock
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
mutex mtx1;
mutex mtx2;
void worker() {lock(mtx1, mtx2); // 同时锁定两个锁unique_lock<mutex> lock1(mtx1, std::adopt_lock); // 需要创建 unique_lock 自动释放锁unique_lock<mutex> lock2(mtx2, std::adopt_lock);cout << "线程进入临界区..." << endl;this_thread::sleep_for(chrono::seconds(1)); // 模拟工作负载cout << "线程退出临界区..." << endl;
}int main() {thread t1(worker);thread t2(worker);t1.join();t2.join();return 0;
} call_once
std::call_once 是 C++11 引入的一个函数模板,用于确保某个操作(如初始化或配置加载)在多线程环境中只被调用一次。它结合了 std::once_flag,能够高效地实现线程安全的单次执行。
基本用法
std::call_once 的函数原型如下:
template <class Callable, class... Args>
void call_once(std::once_flag& flag, Callable&& f, Args&&... args); -
std::once_flag:一个标记对象,用于记录操作是否已经执行过。 -
Callable&& f:需要执行的可调用对象(如函数、lambda 表达式、函数对象等)。 -
Args&&... args:传递给可调用对象的参数。
工作原理
-
首次调用:如果 std::once_flag 标记的操作尚未执行,则 std::call_once 会调用
f,并设置 flag 标记为“已执行”。 -
后续调用:如果 flag 已标记为“已执行”,则后续调用 std::call_once 的线程会直接跳过 f 的执行。
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;std::once_flag flag;
void init(int id) {cout << "Initialization function called once." << endl;cout << "thread " << id << " is running." << endl;
}void worker(int id) {call_once(flag, init,id); // 确保 init 只被调用一次
}int main() {thread t1(worker, 1);thread t2(worker, 2);thread t3(worker, 3);t1.join();t2.join();t3.join();return 0;
} 相关文章:
C++ 互斥锁的使用
mutex std::mutex 是C标准库中用于线程同步的互斥锁机制,主要用于保护共享资源,避免多个线程同时访问导致的竞态条件。 它提供了以下功能: 加锁(lock):阻塞当前线程,直到获取锁。 解锁&#…...
【Elasticsearch】Retrieve inner hits获取嵌套查询的具体的嵌套文档来源,以及父子文档的来源
Retrieve inner hits 是 Elasticsearch 中的一个功能,用于在嵌套查询或父子查询中,返回导致主文档匹配的具体嵌套对象或子/父文档的详细信息,帮助用户更直观地理解查询结果的来源。 在 Elasticsearch 中,Retrieve inner hits是一…...
C语言中的typedef关键字详解
C语言中的typedef关键字详解 在C语言编程中,typedef 关键字是一个非常实用的特性,它可以帮助我们创建新的类型名,从而简化代码,提高可读性。本文将详细解析typedef的使用方法、场景以及注意事项。 1. typedef简介 typedef 是Ty…...
怎麼利用靜態ISP住宅代理在指紋流覽器中管理社媒帳號?
靜態ISP住宅代理是一種基於真實住宅IP的代理服務。這類代理IP通常由互聯網服務提供商(ISP)分配,具有非常高的真實性,與普通數據中心代理相比,更不容易被平臺檢測到為“虛假IP”或“代理IP”,靜態ISP住宅代理…...
【多语言生态篇一】【DeepSeek×Java:Spring Boot微服务集成全栈指南 】
(手把手带你从零实现AI能力调用,万字长文预警,建议收藏实操) 一、环境准备:别输在起跑线上 1.1 硬件软件全家桶 JDK版本:必须 ≥17(Spring Boot 3.2+强制要求,低版本直接报错)IDE推荐:IntelliJ IDEA终极版(社区版缺Spring AI插件支持)构建工具:Maven 3.9+ / Grad…...
IOS UITextField 无法隐藏键盘问题
设置UITextField 键盘按钮返回键为“完成”,即return key 设置done .m代码设置代理 //设置代理协议 UITextFieldDelegate, self.mobileTextField.delegate self; ///点击完成键隐藏键盘 - (BOOL)textFieldShouldReturn:(UITextField *)textField{//取…...
einops测试
文章目录 1. einops2. code3. pytorch 1. einops einops 主要是通过爱因斯坦标记法来处理张量矩阵的库,让矩阵处理上非常简单。 conda : conda install conda-forge::einopspython: 2. code import torch import torch.nn as nn import torch.nn.functional as…...
25轻化工程研究生复试面试问题汇总 轻化工程专业知识问题很全! 轻化工程复试全流程攻略 轻化工程考研复试真题汇总
轻化工程复试心里没谱?学姐带你玩转面试准备! 是不是总觉得老师会问些刁钻问题?别焦虑!其实轻化工程复试套路就那些,看完这篇攻略直接掌握复试通关密码!文中有重点面试题可直接背~ 目录 一、这些行为赶紧避…...
小米路由器 AX3000T 降级后无法正常使用,解决办法
问题描述 买了个 AX3000T 路由器,想安装 OpenWRT 或者 安装 Clash 使用,看教程说是需要降级到 v1.0.47 版本。 结果刷机之后路由器无法打开了,一直黄灯亮,中间灭一下,又是黄灯长亮,没有 WIFI 没有连接。以…...
qt5实现表盘的旋转效果,通过提升QLabel类
因为工作需要,需要实现温度的表盘展示效果 实现思路: 通过提示声QLabel控价类,实现报盘的旋转和展示效果 1. 编写一个QLabel的类MyQLabel,实现两个方法 1. void paintEvent(QPaintEvent *event); //重绘函数 2. void valueChanged(int va…...
【HeadFirst系列之HeadFirst设计模式】第7天之命令模式:封装请求,轻松实现解耦!
命令模式:封装请求,轻松实现解耦! 大家好!今天我们来聊聊设计模式中的命令模式(Command Pattern)。如果你曾经需要将请求封装成对象,或者希望实现请求的撤销、重做等功能,那么命令模…...
HTTPS(下)
主要讲加密算法RSA,ECDHE TLS的握手涉及四次通信,根据不同的密钥交换算法,TLS 握手流程也会不一样的,现在常用的密钥交换算法有两种:RSA 算法和 ECDHE 算法 正常情况下,需要先TCP三次握手后进行TLS四次握手…...
vue2 和 vue3 中 computer 计算属性的用法
Vue 2 中的 computed 在 Vue 2 中,计算属性是响应式的,并且基于 getter 进行缓存,只有依赖的响应式数据发生变化时才会重新计算。 基本用法 <template><div><p>原始消息:{{ message }}</p><p>反…...
【STM32学习】标准库实现STM32 ADC采集1路、2路、多路
目录 ADC采集 ADC配置步骤 STM32F103C8T6的ADC 输入通道 编辑 1路ADC(A4 ADC 通道4) 1路ADC源码代码链接: 2路ADC(A4 ADC 通道4、A5 ADC 通道5)基于DMA实现 多路ADC实现采集 ADC采集 ADC配置步骤 使能GPIO…...
【STM32】外部时钟|红外反射光电开关
1.外部时钟 单片机如何对外部触发进行计数?先看一下内部时钟,内部时钟是接在APB1和APB2时钟线上的,APB1,APB2来自stm32单片机内部的脉冲信号,也叫内部时钟。我们用来定时。同样我们可以把外部的信号接入单片机,来对其…...
【语音科学计算器】当前汇率
JSON_MARKER_HORN{“base”:“USD”,“rates”:{“EUR”:0.9758,“JPY”:157.68,“GBP”:0.8190,“CNY”:7.3327,“HKD”:7.7872,“AUD”:1.6260,“CAD”:1.4422,“CHF”:0.9157,“SGD”:1.3714,“KRW”:1473.05,“NZD”:1.7992,“THB”:34.54,“MYR”:4.4930,“PHP”:57.32,“…...
PHP post 数据丢失问题
max_input_vars是PHP配置选项之一,用于设置一个请求中允许的最大输入变量数。它指定了在处理POST请求或者通过URL传递的参数时,PHP脚本能够接收和处理的最大变量数量。 max_input_vars的默认值是1000,意味着一个请求中最多可以包含1000个输入…...
【云服务器】云服务器内存不够用,开启SWAP交换分区
交换分区(Swap) 1.创建 2GB Swap 文件 sudo fallocate -l 2G /swapfile (如果 fallocate 不支持,可以用 dd 命令) sudo dd if/dev/zero of/swapfile bs1M count2048 2.设置 Swap 权限 sudo chmod 600 /swapfile…...
未来SLAM的研究方向和热点
SLAM(Simultaneous Localization and Mapping)是同时定位与地图构建的缩写,指的是机器人或设备在一个未知环境中一边进行自我定位,一边构建出环境的地图。SLAM广泛应用于机器人、自动驾驶、无人机等领域,涉及多个研究方…...
Orange 单体架构 - 快速启动
1 后端服务 1.1 基础设施 组件说明版本MySQLMySQL数据库服务5.7/8JavaJava17redis-stackRedis向量数据库最新版本Node安装Node22.11.0 1.2 orange-dependencies-parent 项目Maven依赖版本管理 1.2.1 项目克隆 GitHub git clone https://github.com/hengzq/orange-depende…...
7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
图表类系列各种样式PPT模版分享
图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...
使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...
Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...
