C++中的 互斥量
1.概念:
为什么:线程的异步性,不是按照时间来的!!!
C++并发以及多线程的秘密-CSDN博客
目的
多线程编程中,当多个线程可能同时访问和修改共享资源时,会导致数据不一致或程序错误。互斥量提供了一种加锁机制,线程在访问共享资源前必须先获取互斥量的锁,访问结束后释放锁,这样其他线程才能获取锁并访问共享资源。
原理:
互斥量内部维护一个状态,表示它是否被锁定。当一个线程成功获取锁时,互斥量被锁定,其他线程试图获取锁时会被阻塞,直到锁被释放
2.基本用法
C++ 标准库在 <mutex> 头文件中提供了几种类型的互斥量, std::mutex std::timed_mutex
lock函数和unlock函数
#include<mutex>
#include<thread>
#include<iostream>
using namespace std;int sharedResource = 0;
std::mutex mtx;
void increment() {for (int i = 0; i < 10; ++i) {mtx.lock();++sharedResource;cout<<++sharedResource<<endlmtx.unlock();}
}void decrement() {for (int i = 0; i < 10; ++i) {mtx.lock();--sharedResource;cout<<sharedResource<<endl;mtx.unlock();}
}
int main(){std::thread thread1(increment);std::thread thread2(decrement);thread1.join();thread2.join();std::cout << "Final value of sharedResource: " << sharedResource << std::endl;return 0;}
结果如下:
1
2
3
4
5
6
7
8
9
10
9
8
7
6
5
4
3
2
1
0
结果展现清晰知道会有独占思想
2.lock_guard函数
#include <iostream>
#include <mutex>
#include <thread>
using namespace std;std::mutex mtx;
int n=0;void func1() {lock_guard<mutex> lock(mtx);n++;
}
void func2() {lock_guard<mutex> lock(mtx);n--;
}int main() {thread t1(func1);cout << n << endl;thread t2(func2);cout << n << endl;t1.join();t2.join();
}
3.死锁以及解决办法
概念:
死锁是指在多线程或多进程环境中,两个或多个执行单元(线程、进程等)因竞争系统资源或彼此通信而造成的一种阻塞现象,若无外力作用,这些执行单元都将无法推进。
死锁产生的必要条件
-
互斥条件:资源在同一时间只能被一个执行单元使用。例如,打印机在打印一份文档时,不能同时为另一份文档服务。
-
占有并等待条件:一个执行单元持有至少一个资源,并在等待获取其他执行单元持有的额外资源。比如,线程 A 持有资源 R1,同时等待资源 R2,而资源 R2 被线程 B 持有。
-
不可剥夺条件:资源不能被强制从占有者手中夺走,只能由占有者主动释放。例如,一个线程获得了一个文件的独占访问权,其他线程不能强行剥夺这个权限。
-
循环等待条件:存在一个执行单元的循环链,链中的每个执行单元都在等待下一个执行单元持有的资源。例如,线程 A 等待线程 B 持有的资源,线程 B 等待线程 C 持有的资源,而线程 C 又等待线程 A 持有的资源。
#include <iostream>
#include <mutex>
#include <thread>std::mutex mutex1;
std::mutex mutex2;void threadFunction1() {mutex1.lock();std::cout << "Thread 1 has locked mutex1" << std::endl;std::this_thread::sleep_for(std::chrono::seconds(1));mutex2.lock();std::cout << "Thread 1 has locked mutex2" << std::endl;mutex2.unlock();mutex1.unlock();
}void threadFunction2() {mutex2.lock();std::cout << "Thread 2 has locked mutex2" << std::endl;std::this_thread::sleep_for(std::chrono::seconds(1));mutex1.lock();std::cout << "Thread 2 has locked mutex1" << std::endl;mutex1.unlock();mutex2.unlock();
}int main() {std::thread thread1(threadFunction1);std::thread thread2(threadFunction2);thread1.join();thread2.join();return 0;
}
结果//Thread 1 has locked mutex1Thread 2 has locked mutex2
解析:
在上述代码中,threadFunction1 先锁定 mutex1,然后等待 mutex2,而 threadFunction2 先锁定 mutex2,然后等待 mutex1。如果两个线程同时运行,就会满足死锁的四个条件,导致死锁发生。线程 1 持有 mutex1 并等待 mutex2,线程 2 持有 mutex2 并等待 mutex1,形成循环等待,且资源不能被剥夺,从而造成死锁。
如何解决?
利用另外一个lock_guard
std::lock_guard 是基于 RAII(资源获取即初始化)机制的互斥量管理类。它在构造时自动锁定互斥量,在析构时自动解锁,从而简化了代码并避免手动解锁失败的风险
代表adopt_lock 以及手动锁了(就是用lock)
#include <iostream>
#include <mutex>
#include <thread>
using namespace std;std::mutex mutex1;
std::mutex mutex2;
;void threadFunction1() {lock(mutex1,mutex2);lock_guard<mutex>lock1(mutex1,adopt_lock);lock_guard<mutex>lock2(mutex2,adopt_lock);std::cout << "Thread 1 has locked mutex1 and mutex2" << std::endl;std::this_thread::sleep_for(std::chrono::seconds(1));std::cout << "Thread 1 is working with both mutexes" << std::endl;
}void threadFunction2() {lock(mutex1,mutex2);lock_guard<mutex>lock1(mutex2,adopt_lock);lock_guard<mutex>lock2(mutex1,adopt_lock);std::cout << "Thread 1 has locked mutex1 and mutex2" << std::endl;std::this_thread::sleep_for(std::chrono::seconds(1));std::cout << "Thread 1 is working with both mutexes" << std::endl;}int main() {std::thread thread1(threadFunction1);std::thread thread2(threadFunction2);thread1.join();thread2.join();return 0;
}
Thread 1 has locked mutex1 and mutex2
Thread 1 is working with both mutexes
Thread 1 has locked mutex1 and mutex2
Thread 1 is working with both mutexes
4.unique_lock
std::lock_guard是一个简单的 RAII(Resource Acquisition Is Initialization)类,用于在其生命周期内自动锁定和解锁互斥量。它的优点是简单易用,开销小。然而,std::unique_lock提供了更多的功能和灵活性,在很多场景下可以取代std::lock_guard:
-
延迟锁定:
std::unique_lock可以在构造时不立即锁定互斥量,而std::lock_guard在构造时总是立即锁定互斥量。 -
锁定所有权的转移:
std::unique_lock允许通过移动语义转移锁定的所有权,这在函数间传递锁定状态时非常有用。 -
成员函数操作:
std::unique_lock提供了如lock()、try_lock()、try_lock_for()、try_lock_until()和unlock()等成员函数,允许对锁定状态进行更细粒度的控制,而std::lock_guard只在构造和析构时自动锁定和解锁,没有提供这些操作。
4.1三种构造方法
1.std::adopt_lock_t:与std::lock_guard类似,当使用std::adopt_lock作为第二个参数时,表明调用者已经手动锁定了互斥量,std::unique_lock在构造时不会再次锁定,而是在析构时负责解锁。例如:
std::mutex mtx;
mtx.lock();
std::unique_lock<std::mutex> lock(mtx, std::adopt_lock);
2.std::defer_lock_t:使用std::defer_lock作为第二个参数时,std::unique_lock构造时不会锁定互斥量,而是处于未锁定状态。之后可以通过调用lock()、try_lock()等成员函数来锁定互斥量。例如
std::mutex mtx;
std::unique_lock<std::mutex> lock(mtx, std::defer_lock);
if (lock.try_lock()) {// 成功锁定,执行临界区代码lock.unlock();
}
3.std::try_to_lock_t:使用std::try_to_lock作为第二个参数时,std::unique_lock构造时会尝试锁定互斥量,但不会阻塞等待。如果成功锁定,unique_lock对象拥有锁定;否则,处于未锁定状态。例如
std::mutex mtx;
std::unique_lock<std::mutex> lock(mtx, std::try_to_lock);
if (lock.owns_lock()) {// 成功锁定,执行临界区代码lock.unlock();
}
4.2成员函数
-
lock():锁定关联的互斥量。如果互斥量已被锁定,调用线程将阻塞直到互斥量可用。 -
try_lock():尝试锁定关联的互斥量,不会阻塞。如果成功锁定,返回true;否则,返回false。 -
try_lock_for(duration):尝试在指定的时间段内锁定关联的互斥量。如果在指定时间内成功锁定,返回(一般参数为chrono::seconds())同理 -
try_lock_until(time_point) 只能time_mutex用 -
unlock():解锁关联的互斥量。 -
owns_lock():返回unique_lock对象是否拥有互斥量的锁定。 -
release():释放unique_lock对象对互斥量的所有权,返回指向关联互斥量的指针,并且unique_lock对象变为不拥有任何互斥量
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>// 使用 std::timed_mutex 来支持带超时的锁定操作
std::timed_mutex mtx;// 线程函数
void worker(int id) {// 使用 unique_lock 管理互斥量std::unique_lock<std::timed_mutex> lock(mtx, std::defer_lock);// 尝试锁定互斥量,不会阻塞if (lock.try_lock()) {std::cout << "Thread " << id << " acquired the lock using try_lock()." << std::endl;std::this_thread::sleep_for(std::chrono::seconds(1));lock.unlock();} else {std::cout << "Thread " << id << " failed to acquire the lock using try_lock()." << std::endl;}// 尝试在指定时间段内锁定互斥量if (lock.try_lock_for(std::chrono::seconds(2))) {std::cout << "Thread " << id << " acquired the lock using try_lock_for()." << std::endl;std::this_thread::sleep_for(std::chrono::seconds(1));lock.unlock();} else {std::cout << "Thread " << id << " failed to acquire the lock using try_lock_for()." << std::endl;}// 尝试在指定时间点前锁定互斥量auto timeout = std::chrono::steady_clock::now() + std::chrono::seconds(2);if (lock.try_lock_until(timeout)) {std::cout << "Thread " << id << " acquired the lock using try_lock_until()." << std::endl;std::this_thread::sleep_for(std::chrono::seconds(1));lock.unlock();} else {std::cout << "Thread " << id << " failed to acquire the lock using try_lock_until()." << std::endl;}// 正常锁定互斥量lock.lock();std::cout << "Thread " << id << " acquired the lock using lock()." << std::endl;std::this_thread::sleep_for(std::chrono::seconds(1));// 检查是否拥有互斥量的锁定if (lock.owns_lock()) {std::cout << "Thread " << id << " owns the lock." << std::endl;}// 释放 unique_lock 对互斥量的所有权std::timed_mutex* released_mtx = lock.release();if (!lock.owns_lock()) {std::cout << "Thread " << id << " released the lock using release()." << std::endl;}// 手动解锁互斥量released_mtx->unlock();
}int main() {// 创建两个线程std::thread t1(worker, 1);std::thread t2(worker, 2);// 等待线程完成t1.join();t2.join();return 0;
}
相关文章:
C++中的 互斥量
1.概念: 为什么:线程的异步性,不是按照时间来的!!! C并发以及多线程的秘密-CSDN博客 目的 多线程编程中,当多个线程可能同时访问和修改共享资源时,会导致数据不一致或程序错误。…...
直接法估计相机位姿
引入 在前面的文章:运动跟踪——Lucas-Kanade光流中,我们了解到特征点法存在一些缺陷,并且用光流法追踪像素点的运动来替代特征点法进行特征点匹配的过程来解决这些缺陷。而这篇文章要介绍的直接法则是通过计算特征点在下一时刻图像中的位置…...
PHP动态网站建设
如何配置虚拟主机 1. 学习提纲 本地发布与互联网发布:介绍了如何通过本地IP地址和互联网域名发布网站。 虚拟主机配置与访问:讲解了如何配置虚拟主机,并通过自定义域名访问不同的站点目录。 Web服务器配置:详细说明了如何配置A…...
【gRPC】Java高性能远程调用之gRPC详解
gRPC详解 一、什么是gRPC?二、用proto生成代码2.1、前期准备2.2、protobuf插件安装 三、简单 RPC3.1、开发gRPC服务端3.2、开发gRPC客户端3.3、验证gRPC服务 四、服务器端流式 RPC4.1、开发一个gRPC服务,类型是服务端流4.2、开发一个客户端,调…...
数据结构知识学习小结
一、动态内存分配基本步骤 1、内存分配简单示例: 个人对于示例的理解: 定义一个整型的指针变量p(着重认为它是一个“变量”我觉得可能会更好理解),这个变量用来存地址的,而不是“值”,malloc函…...
分布式锁—2.Redisson的可重入锁一
大纲 1.Redisson可重入锁RedissonLock概述 2.可重入锁源码之创建RedissonClient实例 3.可重入锁源码之lua脚本加锁逻辑 4.可重入锁源码之WatchDog维持加锁逻辑 5.可重入锁源码之可重入加锁逻辑 6.可重入锁源码之锁的互斥阻塞逻辑 7.可重入锁源码之释放锁逻辑 8.可重入锁…...
计算机毕业设计SpringBoot+Vue.js球队训练信息管理系统(源码+文档+PPT+讲解)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
FFmpeg入门:最简单的音视频播放器
FFmpeg入门:最简单的音视频播放器 前两章,我们已经了解了分别如何构建一个简单和音频播放器和视频播放器。 FFmpeg入门:最简单的音频播放器 FFmpeg入门:最简单的视频播放器 本章我们将结合上述两章的知识,看看如何融…...
java 查找两个集合的交集部分数据
利用了Java 8的Stream API,代码简洁且效率高 import java.util.stream.Collectors; import java.util.List; import java.util.HashSet; import java.util.Set;public class ListIntersection {public static List<Long> findIntersection(List<Long> …...
【系统架构设计师】以数据为中心的体系结构风格
目录 1. 说明2. 仓库体系结构风格3. 黑板体系结构风格 1. 说明 1.以数据为中心的体系结构风格主要包括仓库体系结构风格和黑板体系结构风格。 2. 仓库体系结构风格 1.仓库(Repository)是存储和维护数据的中心场所。2.在仓库风格中,有两种不…...
通过HTML有序列表(ol/li)实现自动递增编号的完整解决方案
以下是通过HTML有序列表(ol/li)实现自动递增编号的完整解决方案: <!DOCTYPE html> <html> <head> <style> /* 基础样式 */ ol {margin: 1em 0;padding-left: 2em; }/* 方案1:默认数字编号 */ ol.default {list-style-type: dec…...
【Python 数据结构 4.单向链表】
目录 一、单向链表的基本概念 1.单向链表的概念 2.单向链表的元素插入 元素插入的步骤 3.单向链表的元素删除 元素删除的步骤 4.单向链表的元素查找 元素查找的步骤 5.单向链表的元素索引 元素索引的步骤 6.单向链表的元素修改 元素修改的步骤 二、Python中的单向链表 编辑 三…...
基于 vLLM 部署 LSTM 时序预测模型的“下饭”(智能告警预测与根因分析部署)指南
Alright,各位看官老爷们,准备好迎接史上最爆笑、最通俗易懂的 “基于 vLLM 部署 LSTM 时序预测模型的智能告警预测与根因分析部署指南” 吗? 保证让你笑出猪叫,看完直接变身技术大咖!🚀😂 咱们今天的主题,就像是要打造一个“智能运维小管家”! 这个小管家,不仅能提…...
Java多线程与高并发专题——ConcurrentHashMap 在 Java7 和 8 有何不同?
引入 上一篇我们提到HashMap 是线程不安全的,并推荐使用线程安全同时性能比较好的 ConcurrentHashMap。 而在 Java 8 中,对于 ConcurrentHashMap 这个常用的工具类进行了很大的升级,对比之前 Java 7 版本在诸多方面都进行了调整和变化。不过…...
NL2SQL-基于Dify+阿里通义千问大模型,实现自然语音自动生产SQL语句
本文基于Dify阿里通义千问大模型,实现自然语音自动生产SQL语句功能,话不多说直接上效果图 我们可以试着问他几个问题 查询每个部门的员工数量SELECT d.dept_name, COUNT(e.emp_no) AS employee_count FROM employees e JOIN dept_emp de ON e.emp_no d…...
LeetCode 1328.破坏回文串:贪心
【LetMeFly】1328.破坏回文串:贪心 力扣题目链接:https://leetcode.cn/problems/break-a-palindrome/ 给你一个由小写英文字母组成的回文字符串 palindrome ,请你将其中 一个 字符用任意小写英文字母替换,使得结果字符串的 字典…...
计算机视觉|ViT详解:打破视觉与语言界限
一、ViT 的诞生背景 在计算机视觉领域的发展中,卷积神经网络(CNN)一直占据重要地位。自 2012 年 AlexNet 在 ImageNet 大赛中取得优异成绩后,CNN 在图像分类任务中显示出强大能力。随后,VGG、ResNet 等深度网络架构不…...
//定义一个方法,把int数组中的数据按照指定的格式拼接成一个字符串返回,调用该方法,并在控制台输出结果
import java.util.Scanner; public class cha{ public static void main(String[] args){//定义一个方法,把int数组中的数据按照指定的格式拼接成一个字符串返回,调用该方法,并在控制台输出结果//eg: 数组为:int[] arr…...
Python快捷手册
Python快捷手册 后续会陆续更新Python对应的依赖或者工具使用方法 文章目录 Python快捷手册[toc]1-依赖1-词云小工具2-图片添加文字3-BeautifulSoup网络爬虫4-Tkinter界面绘制5-PDF转Word 2-开发1-多线程和队列 3-运维1-Requirement依赖2-波尔实验室3-Anaconda3使用教程4-CentO…...
QT5 GPU使用
一、问题1 1、现象 2、原因分析 出现上图错误,无法创建EGL表面,错误=0x300b。申请不上native window有可能是缺少libqeglfs-mali-integration.so 这个库 3、解决方法 需要将其adb push 到小机端的/usr/lib/qt5/plugins/egldeviceintegrat…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...
