C++多线程编程 3.互斥量、互斥锁

目录

1. 线程安全与互斥锁(std::mutex)

2. 互斥量死锁

3. std::lock_guard

4. std::unique_lock

(1)示例

 (2)详细知识点

5. std::this_thread

(1)sleep_for

(2)sleep_until

(3)yield

(4)get_id


直接通过示例讲解:

1. 线程安全与互斥锁(std::mutex

int a = 0;
std::mutex mtx;
void func1()
{for (int i = 0; i < 1000; i++){mtx.lock(); // 加锁a += 1;mtx.unlock(); // 解锁}
}

线程安全问题:在多线程环境中,如果多个线程同时访问和修改同一个共享变量(如这里的 a),可能会导致数据竞争,产生不可预期的结果。

如果多个线程同时访问同一个变量,并且其中至少有一个线程对该变量进行了写操作,那么就会出现数据竞争问题。

 

数据竞争可能会导致程序崩溃、产生未定义的结果,或者得到错误的结果。

 

为了避免数据竞争问题,需要使用同步机制来确保多个线程之间对共享数据的访问是安全的。常见的同步机制包括互斥量、条件变量、原子操作等。

std::mutex:互斥锁是一种同步原语,用于保护共享资源。

mtx.lock() 会尝试锁定互斥锁,如果锁已经被其他线程持有,当前线程会被阻塞,直到锁被释放。

mtx.unlock() 用于释放锁,允许其他线程获取该锁。

使用方式:在修改共享变量 a 之前调用 mtx.lock() 加锁,修改完成后调用 mtx.unlock() 解锁,确保同一时间只有一个线程可以修改 a,从而保证线程安全。

2. 互斥量死锁

mutex m1, m2;
void func2()
{for (int i = 0; i < 50; i++){m1.lock();m2.lock();m1.unlock();m2.unlock();}
}void func3()
{for (int i = 0; i < 50; i++){m2.lock();m1.lock();m2.unlock();m1.unlock();}
}

死锁原理:死锁是指两个或多个线程在执行过程中,因争夺资源而造成的一种互相等待的现象。在 func2 中,线程先锁定 m1 再锁定 m2;而在 func3 中,线程先锁定 m2 再锁定 m1。如果两个线程同时执行,可能会出现 func2 持有 m1 等待 m2,而 func3 持有 m2 等待 m1 的情况,从而导致死锁。

解决方法:为了避免死锁,所有线程应该按照相同的顺序获取锁,例如都先获取 m1 再获取 m2

3. std::lock_guard

#include <iostream>
#include <thread>
#include <mutex>
#include <vector>std::mutex mtx3;
int b = 0;void fun5()
{for (int i = 0; i < 10000; i++){std::lock_guard<std::mutex> lg(mtx3);b++;}
}int main()
{const int numThreads = 5;  // 定义线程数量std::vector<std::thread> threads;// 创建并启动线程for (int i = 0; i < numThreads; i++){threads.emplace_back(fun5);}// 等待所有线程执行完毕for (auto& thread : threads){thread.join();}// 输出最终结果std::cout << "Final value of b: " << b << std::endl;std::cout << "Expected value of b: " << 10000 * numThreads << std::endl;return 0;
}

作用std::lock_guard 是一个 RAII(资源获取即初始化)风格的类模板,用于自动管理互斥锁的加锁和解锁操作。

工作原理:当创建 std::lock_guard 对象时,它会在构造函数中自动调用互斥锁的 lock() 方法加锁;当 std::lock_guard 对象离开其作用域时,它会在析构函数中自动调用互斥锁的 unlock() 方法解锁。这样可以避免手动调用 lock() 和 unlock() 可能导致的忘记解锁问题,提高代码的安全性。

4. std::unique_lock

(1)示例

#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
#include <vector>int c = 0;
std::timed_mutex mtx6;void func6() {for (int i = 0; i < 5000; i++) {std::unique_lock<std::timed_mutex> lg(mtx6, std::defer_lock);std::this_thread::sleep_for(std::chrono::seconds(5));if (lg.try_lock_for(std::chrono::seconds(5))) {c++;lg.unlock();}}
}int main() {const int numThreads = 3;std::vector<std::thread> threads;// 创建并启动线程for (int i = 0; i < numThreads; i++) {threads.emplace_back(func6);}// 等待所有线程执行完毕for (auto& thread : threads) {thread.join();}// 输出最终结果std::cout << "Final value of c: " << c << std::endl;std::cout << "Expected value of c: " << 5000 * numThreads << std::endl;return 0;
}

特点std::unique_lock 也是一个用于管理互斥锁的 RAII 类,但它比 std::lock_guard 更加灵活,包括延迟加锁、条件变量、超时等

std::unique_lock<std::timed_mutex> lg(mtx6, std::defer_lock);

创建一个 std::unique_lock 对象 lg,用于管理 mtx6 互斥锁。

参数 defer_lock:在创建 std::unique_lock 对象时,传递 defer_lock 参数表示不自动加锁,需要手动调用 lock() 或 try_lock() 等方法来加锁。

 

std::this_thread::sleep_for(std::chrono::seconds(5));

当前线程暂停执行 5 秒钟。

 

lg.try_lock_for(std::chrono::seconds(5));

try_lock_fortry_lock_for 是 std::unique_lock 提供的一个方法,用于尝试在指定的时间内锁定互斥锁。代码中的含义是:尝试在 5 秒内锁定互斥锁。如果在 5 秒内成功锁定,则返回 true,否则返回 false

 (2)详细知识点

1.灵活的锁定策略

可以在创建 std::unique_lock 对象时选择是否立即锁定互斥锁。例如:

std::mutex mtx;
std::unique_lock<std::mutex> lock1(mtx); // 立即锁定互斥锁
std::unique_lock<std::mutex> lock2(mtx, std::defer_lock); // 不立即锁定互斥锁

2. 支持锁的转移

可以将一个 std::unique_lock 对象的锁所有权转移给另一个 std::unique_lock 对象。例如:

std::mutex mtx;
std::unique_lock<std::mutex> lock1(mtx);
std::unique_lock<std::mutex> lock2(std::move(lock1)); // 转移锁所有权

3. 支持带超时的锁定操作

如果使用的是 std::timed_mutex 或 std::recursive_timed_mutex,可以使用 try_lock_for 和 try_lock_until 方法进行带超时的锁定操作。例如:

std::timed_mutex mtx;
std::unique_lock<std::timed_mutex> lock(mtx, std::defer_lock);
if (lock.try_lock_for(std::chrono::seconds(2))) {// 成功锁定互斥锁
} else {// 锁定超时
}

 

5. std::this_thread

std::this_thread 是 C++ 标准库中的一个命名空间,提供了与当前线程相关的一些实用函数。

(1)sleep_for

使当前线程暂停执行指定的时间段。例如:

std::this_thread::sleep_for(std::chrono::seconds(2)); // 线程暂停 2 秒

(2)sleep_until

使当前线程暂停执行直到指定的时间点。例如:

auto wake_time = std::chrono::steady_clock::now() + std::chrono::seconds(3);
std::this_thread::sleep_until(wake_time); // 线程暂停到指定时间点

(3)yield

当前线程放弃执行权,允许其他线程执行。例如:

std::this_thread::yield(); // 当前线程让出 CPU 时间片

(4)get_id

返回当前线程的唯一标识符。例如:

std::thread::id this_id = std::this_thread::get_id();
std::cout << "Current thread ID: " << this_id << std::endl;

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/71998.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【redis】hash基本命令和内部编码

文章目录 表示形式命令HSET 和 HGET HEXISTSHDELHKEYSHVALSHGETALLHMGETHLENHSETNXHINCRBYHINCRBYFLOAT命令小结内部编码 表示形式 Redis 自身已经是键值对结构了 Redis 自身的键值对就是通过哈希的方式来组织的 把 key 这一层组织完成之后&#xff0c;到了 value 这一层&…

行为模式---策略模式

概念 策略模式是一种行为设计摸是&#xff0c;它的核心思想是将一些列的算法封装成独立的对象&#xff0c;并使它们可以相互替换&#xff0c;通过上下文进行调用。 策略模式通过算法抽象为独立的策略类&#xff0c;客户端可以根据自身需求选择不同的策略类来完成任务、这种方…

Selenium 自动化测试学习总结

大概了解一下即可&#xff0c;现在主要用的自动化工具是 playWright&#xff0c;它可以录制操作。 selenium是老款自动化测试工具&#xff0c;仍有很多可取之处。 安装&#xff1a; pip install selenium即可。然后下载浏览器的驱动包&#xff0c;注意不是浏览器&#xff01;…

四层协议攻防手册:从SYN Flood到UDP反射的深度防御

一、四层协议攻击类型与特征 攻击类型协议层特征SYN FloodTCP大量半开连接&#xff0c;SYN_RECV状态堆积UDP反射放大UDP小请求包触发大响应&#xff08;如NTP、DNS响应&#xff09;TCP分片攻击TCP发送异常分片耗尽重组资源连接耗尽攻击TCP建立大量空闲连接占用端口资源 二、TC…

【社区投稿】深入再谈智能指针、AsRef引用与Borrow借用

深入再谈智能指针、AsRef引用与Borrow借用 这是一个具有深度的技术主题。每次重温其理论知识&#xff0c;都会有新的领悟。大约 2 年前&#xff0c;我曾就这一技术方向撰写过另一篇短文《从类型转换视角&#xff0c;浅谈Deref<Target T>, AsRef<T>, Borrow<T&g…

外层元素旋转,其包括在内的子元素一并旋转(不改变旋转中心),单元测试

思路&#xff1a;外层旋转后坐标&#xff0c;元素旋转后坐标&#xff0c;计算偏移坐标 <template><div class"outbox"><label>角度: <input v-model.number"rotate" type"number" /></label><br><div c…

如何在虚拟机上安装hadoop

与前面java的方式相同安装好hadoop后进入hadoop的环境变量my_env.sh 输入#​HADOOP_export HADOOP_HOME /opt/module/hadoop-3.1.3 export PATH$PATH:$HADOOP_HOME/bin export PATH$PATH:$HADOOP_HOME/sbin 再输入hadoop测试是否安装成功

WPF-DataGrid的增删查改

背景&#xff1a;该功能为几乎所有系统开发都需要使用的功能&#xff0c;现提供简单的案例。 1、MyCommand using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Input;namespace Wp…

Oracle数据库存储结构--物理存储结构

数据库存储结构&#xff1a;分为物理存储结构和逻辑存储结构。 物理存储结构&#xff1a;操作系统层面如何组织和管理数据 逻辑存储结构&#xff1a;Oracle数据库内部数据组织和管理数据&#xff0c;数据库管理系统层面如何组织和管理数据 存储结构 在Oracle数据库的存储结构…

歌词相关实现

歌词相关 歌词数据模型&#xff1a; // Lyric.swift class Lyric: BaseModel {/// 是否是精确到字的歌词var isAccurate:Bool false/// 所有的歌词var datum:Array<LyricLine>! }// LyricLine.swift class LyricLine: BaseModel {/// 整行歌词var data:String!/// 开始…

纺织服装制造行业现状 内检实验室系统在纺织服装制造行业的应用

在纺织服装制造行业&#xff0c;内检实验室LIMS系统&#xff08;实验室信息管理系统&#xff09;已成为提升检测效率、优化质量控制和满足行业合规性要求的关键工具。随着行业竞争的加剧和消费者对产品质量要求的提高&#xff0c;纺织服装制造企业需要更加高效、准确的检测流程…

K8s 1.27.1 实战系列(十一)ConfigMap

ConfigMap 是 Kubernetes 中管理非敏感配置的核心资源,通过解耦应用与配置实现灵活性和可维护性。 一、ConfigMap 的核心功能及优势 ​1、配置解耦 将配置文件(如数据库地址、日志级别)与容器镜像分离,支持动态更新而无需重建镜像。 ​2、多形式注入 ​环境变量:将键值…

3分钟复现 Manus 超强开源项目 OpenManus

文章目录 前言什么是 OpenManus构建方式环境准备克隆代码仓库安装依赖配置 LLM API运行 OpenManus 效果演示总结个人简介 前言 近期人工智能领域迎来了一位备受瞩目的新星——Manus。Manus 能够独立执行复杂的现实任务&#xff0c;无需人工干预。由于限制原因大部分人无法体验…

从零开始学机器学习——构建一个推荐web应用

首先给大家介绍一个很好用的学习地址:https://cloudstudio.net/columns 今天,我们终于将分类器这一章节学习完活了,和回归一样,最后一章节用来构建web应用程序,我们会回顾之前所学的知识点,并新增一个web应用用来让模型和用户交互。所以今天的主题是美食推荐。 美食推荐…

【最后203篇系列】014 AI机器人-1

说明 终于开张了&#xff0c;我觉得AI机器人是一件真正正确&#xff0c;具有商业价值的事。 把AI机器人当成一笔生意&#xff0c;我如何做好这笔生意&#xff1f;一端是业务价值&#xff0c;另一端是技术支撑。如何构造高质量的内容和服务&#xff0c;如何确保技术的广度和深度…

【大模型统一集成项目】如何封装多个大模型 API 调用

&#x1f31f; 在这系列文章中&#xff0c;我们将一起探索如何搭建一个支持大模型集成项目 NexLM 的开发过程&#xff0c;从 架构设计 到 代码实战&#xff0c;逐步搭建一个支持 多种大模型&#xff08;GPT-4、DeepSeek 等&#xff09; 的 一站式大模型集成与管理平台&#xff…

AI4CODE】3 Trae 锤一个贪吃蛇的小游戏

【AI4CODE】目录 【AI4CODE】1 Trae CN 锥安装配置与迁移 【AI4CODE】2 Trae 锤一个 To-Do-List 这次还是采用 HTML/CSS/JAVASCRIPT 技术栈 Trae 锤一个贪吃蛇的小游戏。 1 环境准备 创建一个 Snake 的子文件夹&#xff0c;清除以前的会话记录。 2 开始构建 2.1 输入会…

【简答题002】Java变量简答题

博主会经常补充完善这里面问题的答案。希望可以得到大家的一键三连支持&#xff0c;你的鼓励是我坚持下去的最大动力&#xff01;谢谢&#xff01; 001 什么是Java变量&#xff1f; Java变量是用来存储数据并在程序中引用的命名空间。 002 Java变量有哪些类型&#xff1f; J…

从零开发Chrome广告拦截插件:开发、打包到发布全攻略

从零开发Chrome广告拦截插件&#xff1a;开发、打包到发布全攻略 想打造一个属于自己的Chrome插件&#xff0c;既能拦截烦人的广告&#xff0c;又能优雅地发布到Chrome Web Store&#xff1f;别担心&#xff0c;这篇教程将带你从零开始&#xff0c;动手开发一个功能强大且美观…

基于腾讯云高性能HAI-CPU的跨境电商客服助手全链路解析

跨境电商的背景以及痛点 根据Statista数据&#xff0c;2025年全球跨境电商市场规模预计达6.57万亿美元&#xff0c;年增长率保持在12.5% 。随着平台规则趋严&#xff08;如亚马逊封店潮&#xff09;&#xff0c;更多卖家选择自建独立站&#xff0c;2024年独立站占比已达35%。A…