【C++入门到精通】互斥锁 (Mutex) C++11 [ C++入门 ]

news2025/2/5 12:40:08

在这里插入图片描述

阅读导航

  • 引言
  • 一、Mutex的简介
  • 二、Mutex的种类
    • 1. std::mutex (基本互斥锁)
    • 2. std::recursive_mutex (递归互斥锁)
    • 3. std::timed_mutex (限时等待互斥锁)
    • 4. std::recursive_timed_mutex (限时等待递归互斥锁)
  • 三、总结
  • 温馨提示

引言

在多线程编程中,保证数据的同步和互斥是至关重要的。而互斥锁(Mutex)作为一种常用的同步机制,在C++11标准中被引入,提供了一种简单有效的方式来控制多个线程对共享资源的访问。互斥锁可以确保同一时间只有一个线程可以持有锁,并且其他线程需要等待锁释放后才能继续执行,从而避免了多个线程同时访问共享资源所导致的数据竞争和不一致性问题。本文将详细介绍互斥锁的种类、使用方法以及一些常见的注意事项,帮助读者更好地理解和应用互斥锁来实现线程安全的程序。

一、Mutex的简介

⭕Mutex官方文档
在这里插入图片描述
Mutex(互斥量)是一种同步原语,用于实现多线程环境下的资源互斥访问。它允许多个线程同时访问共享资源,但在任何给定时间只能有一个线程能够获得对该资源的独占访问权。Mutex主要用于防止数据竞争和确保数据的一致性。

在C++11之前,开发人员通常使用操作系统提供的互斥机制来实现线程间的同步。而C++11引入的Mutex则提供了一种标准化的、跨平台的解决方案,使得多线程编程更加简单和可靠。

Mutex的基本操作包括锁定(lock)和解锁(unlock)。当一个线程需要访问共享资源时,它会尝试对Mutex进行加锁操作,如果Mutex已经被其他线程锁定,那么该线程将被阻塞,直到Mutex被解锁。一旦线程完成对共享资源的操作,它会释放Mutex,允许其他线程获得对资源的访问权。

使用Mutex可以有效地避免数据竞争和保护共享资源的一致性。然而,Mutex也存在一些潜在问题,如死锁(deadlock)和饥饿(starvation)。为了避免这些问题,开发人员需要仔细设计和管理Mutex的使用,并采用合适的同步机制。

二、Mutex的种类

⭕在C++11中,Mutex总共包了四个互斥量的种类分别是:

Mutex类型描述
std::mutex最基本的互斥锁类型,用于实现线程间的互斥访问。只允许一个线程获得锁,其他线程需要等待锁被释放才能继续执行。
std::recursive_mutex与std::mutex类似,但允许同一线程多次获取锁。也就是说,同一线程可以多次对该锁进行加锁操作,每次加锁都需要对应的解锁操作。
std::timed_mutex可限时等待的互斥锁类型。与std::mutex类似,但允许线程在尝试获取锁时设置一个超时时间。如果锁在指定的时间内无法被获得,线程将不再等待并返回相应的错误代码。
std::recursive_timed_mutex可限时等待的递归互斥锁类型。结合了std::recursive_mutex和std::timed_mutex的特性,允许同一线程多次获取锁,并且可以设置超时时间。

以上是四种常见的Mutex类型及其描述,适用于不同的场景,下面我会详细介绍这四个Mutex类型。

1. std::mutex (基本互斥锁)

std::mutex是C++标准库中提供的最基本的互斥锁类型之一。它用于实现线程间的互斥访问,即在一个时间点只允许一个线程获得锁,其他线程需要等待锁被释放才能继续执行。使用std::mutex可以保证多个线程对共享资源的访问顺序,并避免数据竞争产生的问题。

🚨注意该类的对象之间不能拷贝,也不能进行移动

std::mutex最常用的三个函数是

函数名描述
lock()尝试获取互斥锁。如果未被其他线程占用,则当前线程获取锁;否则阻塞等待锁的释放。
unlock()释放互斥锁。如果当前线程持有锁,则释放锁;否则行为未定义。
try_lock()尝试获取互斥锁,不会阻塞线程。如果未被其他线程占用,则当前线程获取锁并返回true;否则返回false。

这三个函数组成了基本的互斥锁操作,也是使用std::mutex时最常用的三个函数。其中,lock()和unlock()通常需要成对使用,以确保锁得到正确的管理。try_lock()则可以用于一些特殊情况下的非阻塞式加锁操作,例如在轮询等待某个资源时,可以尝试获取锁并立即返回结果。

🚨注意事项

  1. 线程函数调用lock()时,可能会发生以下三种情况:
    • 如果该互斥量当前没有被锁住,则调用线程将该互斥量锁住,直到调用 unlock之前,该线程一直拥有该锁。
    • 如果当前互斥量被其他线程锁住,则当前的调用线程被阻塞住。
    • 如果当前互斥量被当前调用线程锁住,则会产生死锁(deadlock)
  2. 线程函数调用try_lock()时,可能会发生以下三种情况:
    • 如果当前互斥量没有被其他线程占有,则该线程锁住互斥量,直到该线程调用 unlock释放互斥量。
    • 如果当前互斥量被其他线程锁住,则当前调用线程返回 false,而并不会被阻塞掉。
    • 如果当前互斥量被当前调用线程锁住,则会产生死锁(deadlock)

2. std::recursive_mutex (递归互斥锁)

std::recursive_mutex是C++标准库中提供的一个递归互斥锁类型,用于实现线程间的互斥访问。与std::mutex相比,std::recursive_mutex可以允许同一线程多次获取互斥锁,而不会导致死锁。简单来说就是允许同一个线程对互斥量多次上锁(即递归上锁),来获得对互斥量对象的多层所有权,释放互斥量时需要调用与该锁层次深度相同次数的 unlock()

std::recursive_mutex定义在<mutex>头文件中。与std::mutex类似,可以通过定义std::recursive_mutex对象来创建一个递归互斥锁。例如:

#include <mutex>
//这里定义了一个名为mtx的std::recursive_mutex对象,用于保护某个共享资源的访问。
std::recursive_mutex mtx;

std::recursive_mutex的主要方法和std::mutex相同,包括lock()unlock()try_lock()。这些方法的功能和使用方式也与std::mutex一致。区别在于,当同一线程多次尝试获取std::recursive_mutex时,它不会导致死锁,而是允许同一线程多次获取锁,需要相应次数的解锁操作才能完全释放锁

3. std::timed_mutex (限时等待互斥锁)

std::timed_mutex是C++标准库中提供的一个可超时等待的互斥锁类型,用于实现线程间的互斥访问。与std::mutex相比,std::timed_mutex在尝试获取锁的时候可以设置超时时间,避免线程由于无法获取锁而一直被阻塞等待,从而提高程序的健壮性。

std::timed_mutex定义在<mutex>头文件中。与std::mutex类似,可以通过定义std::timed_mutex对象来创建一个可超时等待的互斥锁。例如:

#include <mutex>
//这里定义了一个名为mtx的std::timed_mutex对象,用于保护某个共享资源的访问。
std::timed_mutex mtx;

std::timed_mutex的主要方法和std::mutex相同,包括lock()unlock()try_lock()。不同的是,std::timed_mutex提供了try_lock_for()try_lock_until()这两个方法,用于在指定的时间范围内尝试获取互斥锁。

try_lock_for()方法允许线程尝试在指定的时间段内获取互斥锁,如果在指定时间内无法获取锁,则返回false。例如:

std::timed_mutex mtx;
std::chrono::milliseconds timeout(100);

if (mtx.try_lock_for(timeout)) 
{
    // 成功获取锁
    // ...
    mtx.unlock(); // 释放锁
} 
else 
{
    // 超时等待,未能获取锁
    // ...
}

try_lock_until()方法允许线程尝试在指定的时间点之前获取互斥锁,如果在指定时间点之前无法获取锁,则返回false。例如:

std::timed_mutex mtx;
std::chrono::system_clock::time_point deadline = std::chrono::system_clock::now() + std::chrono::milliseconds(100);

if (mtx.try_lock_until(deadline)) 
{
    // 成功获取锁
    // ...
    mtx.unlock(); // 释放锁
} 
else 
{
    // 超时等待,未能获取锁
    // ...
}

4. std::recursive_timed_mutex (限时等待递归互斥锁)

std::recursive_timed_mutex是C++11标准库中提供的一个可递归、可超时等待的互斥锁类型,它是std::timed_mutex的另一个版本。与std::timed_mutex一样,std::recursive_timed_mutex用于实现线程间的互斥访问,但它允许同一线程多次获取锁,从而避免死锁等问题。

std::recursive_timed_mutex定义在<mutex>头文件中。和std::timed_mutex类似,可以通过定义std::recursive_timed_mutex对象来创建一个可递归、可超时等待的互斥锁。例如:

#include <mutex>
//这里定义了一个名为mtx的std::recursive_timed_mutex对象,用于保护某个共享资源的访问。
std::recursive_timed_mutex mtx;

std::recursive_timed_mutex的主要方法和std::timed_mutex相同,包括lock()unlock()try_lock()。不同的是,std::recursive_timed_mutex允许同一线程多次获取锁,从而避免死锁等问题。例如:

void foo()
{
    std::unique_lock<std::recursive_timed_mutex> lock(mtx);
    // ...
    bar(); // 调用另一个函数
    // ...
}

void bar()
{
    std::unique_lock<std::recursive_timed_mutex> lock(mtx); // 可以再次获取锁
    // ...
}

在上面的例子中,foo()函数和bar()函数都使用了std::unique_lock对象来获取mtx互斥锁。由于std::recursive_timed_mutex允许同一线程多次获取锁,因此bar()函数可以再次获取锁,而不会导致死锁等问题。

std::timed_mutex类似,std::recursive_timed_mutex也提供了try_lock_for()try_lock_until()方法,用于在指定的时间范围内尝试获取锁。例如:

std::recursive_timed_mutex mtx;
std::chrono::milliseconds timeout(100);

if (mtx.try_lock_for(timeout)) 
{
    // 成功获取锁
    // ...
    mtx.unlock(); // 释放锁
} 
else 
{
    // 超时等待,未能获取锁
    // ...
}

🚨注意由于std::recursive_timed_mutex允许同一线程多次获取锁,因此在释放锁之前,必须将锁计数器减少到零。否则,其他线程将无法获取到锁,从而导致死锁等问题

三、总结

在使用互斥锁时,需要注意正确地加锁和解锁,以避免资源竞争和死锁等问题的发生。在大多数情况下,应优先选择最简单的互斥锁类型std::mutex只有在需要递归、限时等待功能时才考虑其他类型。选择互斥锁类型应根据具体需求和场景来进行。

通过合理使用互斥锁,可以保证多线程程序的正确性和稳定性,提高多线程程序的性能和并发能力

温馨提示

感谢您对博主文章的关注与支持!另外,我计划在未来的更新中持续探讨与本文相关的内容,会为您带来更多关于C++以及编程技术问题的深入解析、应用案例和趣味玩法等。请继续关注博主的更新,不要错过任何精彩内容!

再次感谢您的支持和关注。期待与您建立更紧密的互动,共同探索C++、算法和编程的奥秘。祝您生活愉快,排便顺畅!
在这里插入图片描述

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

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

相关文章

残差网络学习

参考B站同济子豪兄的Resnet讲解 网络退化&#xff0c;不是梯度消失&#xff08;根本没有开始学习&#xff09;&#xff0c;梯度爆炸&#xff0c;过拟合。 不需要再拟合复杂底层的那个映射了&#xff0c;原来输入的基础上你需要进行哪些偏移哪些修改 残差预测值和真实值的偏差 一…

全光谱全天候耐久性性能测试氙灯老化箱太阳光模拟器

氙灯老化箱应用领域 添加剂 & 着色剂胶粘剂 & 密封剂建材汽车食品& 饮料平面艺术 包装材料油漆& 涂料光伏塑料纺织品风能 & 太阳能消费类电子产品 氙灯老化箱描述 氙灯老化箱是一种用于模拟阳光、雨水和温度循环的老化测试设备。它使用氙灯作为光源&am…

Docker概述及介绍

Docker是近年来新兴的虚拟化工具&#xff0c;它可以和虚拟机一样实现资源和系统环境的隔离。 库&#xff0c;然后再安装应用&#xff1b; Container(Docker容器)&#xff0c;在宿主机器、宿主机器操作系统上创建Docker引擎&#xff0c;在引擎的基础上再安装应用。 Docker三…

【第七在线】可持续时尚与商品计划:减少库存浪费的方法

随着可持续时尚的崭露头角&#xff0c;服装企业越来越重视减少库存浪费。库存浪费不仅对环境造成负面影响&#xff0c;还对企业的经济可持续性产生负面影响。本文将深入探讨可持续时尚与商品计划之间的关系&#xff0c;以及一些减少库存浪费的方法&#xff0c;有助于改进商品计…

Spring事务管理—讲解、案例、应用

简介&#xff1a;Spring事务管理和数据库的事务管理的功能作用上是一样的&#xff0c;在学习数据库时&#xff0c;为了数据完整性&#xff0c;采用了事务管理&#xff0c;即开启事务、提交事务和管理事务。在SpringBoot框架中添加一个注解 Transactional 就可以将当前方法、类和…

MySQL数据库-概括与常用图形管理工具

文章目录 一、SQL语言基础二、数据库系统三、MySQL数据库概括三、MySQL数据库常用图形管理工具 一、SQL语言基础 二、数据库系统 三、MySQL数据库概括 三、MySQL数据库常用图形管理工具 官网&#xff1a;https://www.navicat.com/en 官网&#xff1a;https://webyog.com/produ…

C++——C++11(2)

我在我的C异常博客中曾提到&#xff0c;对于异常的处理经常会导致内存泄漏问题&#xff0c; 一种解决方法是异常的重新抛出&#xff0c;还有一种就是RAII&#xff0c;那么RAII的思想体现 在C中就是智能指针&#xff0c;所以接下来我将简单的介绍&#xff0c;什么是RAII&#xf…

工具推荐:有哪些好用的SEO工具?

在现如今竞争激烈的互联网时代&#xff0c;网站优化是每个企业都需要关注的重要方面。为了提高网站在搜索引擎中的排名和曝光度&#xff0c;SEO&#xff08;搜索引擎优化&#xff09;工具成为了必不可少的帮手。本文将为大家推荐3款好用的SEO工具&#xff0c;感兴趣就接着往下看…

c++ qt 模态框和阻拦器 优先级 问题 修复 已解决

在c项目中。有 加载动画 和 模态框提醒的功能, 导致发生一个问题&#xff0c;有提示框的时候&#xff0c;动画也停止&#xff0c;必须点击 按钮 所有代码才能有效。 解决办法 谨慎使用 deleteLater,因为和模态框拦截有冲突, 使用 隐藏 或者 删除指针。 deleteLater 使用逻辑是 …

docker数据卷数据卷容器

前言 今天调休在家&#xff0c;随便玩玩&#xff0c;简单做下学习记录 1. 数据卷特点 数据卷在容器启动时初始化&#xff0c;如果容器使用的镜像在挂载点包含了数据&#xff0c;这些数据会被拷贝到新初始化的数据卷中数据卷可以在容器之间共享和重用可以对数据卷里的内容直接…

二分查找法详解(6种变形)

前言 在之前的博客中&#xff0c;我给大家介绍了最基础的二分查找法&#xff08;没学的话点我点我&#xff01;&#xff09; 今天我将带大家学习二分法的六种变形如何使用&#xff0c;小伙伴们&#xff0c;快来开始今天的学习吧&#xff01; 文章目录 1&#xff0c;查找第一个…

【动画图解】一次理清九大排序算法!面试官问到再也不慌!

排序算法 交换排序 冒泡排序快速排序 插入排序 直接插入排序希尔排序 选择排序 简单选择排序堆排序 归并排序基数排序桶排序 一、冒泡排序 冒泡排序是一种简单的交换排序算法&#xff0c;以升序排序为例&#xff0c;其核心思想是&#xff1a; 从第一个元素开始&#xff0c…

基于ssm二手车交易平台的设计论文

摘 要 进入21世纪网络和计算机得到了飞速发展&#xff0c;并和生活进行了紧密的结合。目前&#xff0c;网络的运行速度以达到了千兆&#xff0c;覆盖范围更是深入到生活中的角角落落。这就促使二手交易网站的发展。二手交易网站可以实现远程购物&#xff0c;远程选择喜欢的商品…

MACBOOK 通过iterm2连接堡垒机跳转服务器

本公司是通过齐治堡垒机连接远程服务器的环境&#xff0c;因为连接过程中需要自动输入密码和选择主机&#xff0c;所以要使用expect工具&#xff0c;编写expect脚本remote.exp #!/usr/bin/expectif { $argc ! 7 } {send_user "usage: expect $argv0 \[JUMP_HOST\] \[JUM…

算法模板之栈图文详解

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;算法模板、数据结构 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. ⛳️模拟栈1.1 &#x1f514;用数组模拟实现栈1.1.1 &#x1f47b;栈的定义1.1.…

window安装n报错

window11安装 n 时报以下错误 Unsupported platform for n9.2.0: wanted {“os”:“!win32”} (current: {“os”:“win32”}) 虽然执行 npm -g install n --force 可以强制安装 n&#xff0c;但是安装完成后&#xff0c;执行命令还是会报以下错误 ‘“bash”’ 不是内部或外部…

使用【OpenI启智平台】进行模型训练

前言 启智平台OpenI是一个人工智能开源开放平台&#xff0c;提供免费GPU算力可以进行模型训练。模式是git进行项目管理&#xff0c;可以创建调试任务调试代码以及保存镜像&#xff0c;创建训练任务训练模型&#xff0c;也提供推理和评测&#xff0c;我没用过就不讲述了。后来我…

多层负载均衡实现

1、单节点负载均衡 1&#xff09;站点层与浏览器层之间加入了一个反向代理层&#xff0c;利用高性能的nginx来做反向代理 2&#xff09;nginx将http请求分发给后端多个web-server 优点&#xff1a; 1&#xff09;DNS-server不需要动 2&#xff09;负载均衡&#xff1a;通过ngi…

docker-compose部署NebulaGraph图数据库

一、linux安装docker-compose 1.下载Docker Compose的可执行文件。可以使用以下命令下载最新版本&#xff1a; sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-comp…

25年老品牌 美好蕴育润康守护孕期妈妈的健康之路

孕期是每一位女性人生中最为特殊的阶段。每一位妈妈都期待着健康、快乐的度过每一天。然而&#xff0c;随着孕周的增加&#xff0c;孕期的不适和困扰也随之而来。孕吐、腰酸背痛、便秘等孕期症状让许多妈妈倍感疲惫和焦虑。在这个关键时刻&#xff0c;美好蕴育润康作为25年的老…