C++新特性34_递归互斥量recursive_mutex与超时互斥量timed_mutex的使用(递归互斥量解决同一线程重复使用互斥量的需求;超时互斥量设置等待超时机制;解决互斥量阻塞问题)

2023-11-13

接上篇C++新特性33_死锁产生的原因及避免(线程在等待一个永远都不能成功的条件成立,从而进入到陷入休眠,永远不能被唤醒的状态、通过调整锁的使用顺序解决死锁问题),本篇将会学习互斥体的相关知识。

1. 互斥量

在C++11中除了提供mutex之外还会提供其他三种加强版的mutex,C++11 中提供以下4种语义的互斥量(mutex):

  • std::mutex: 独占的互斥量,不能递归使用
  • std::recursive_mutex: 递归互斥量,不带超时功能
  • std::timed_mutex: 带超时的独占互斥量,不能递归使用
  • std::recursive_timed_mutex: 带超时的递归互斥量。

2. 互斥量重入问题

先看一段代码:

#include "stdafx.h"
#include <iostream>           // std::cout
#include <thread>             // std::thread
#include <mutex>              // std::mutex, std::unique_lock
#include <future>

using namespace std;

class CTest{
public:
    void foo1() {
        m_mtx.lock();
        std::cout << "foo1" << std::endl;
        m_mtx.unlock();
    }

    void foo2() {
        m_mtx.lock();
        std::cout << "foo2" << std::endl;
        m_mtx.unlock();
    }

private:
    std::mutex m_mtx;
};

int main()
{
    //主线程
    CTest t;

    t.foo1();

    t.foo2();

    return 0;
}

运行结果:程序依次进入t.foo1()和t.foo2()
在这里插入图片描述
研究一个问题,是否可以重复上锁?

void foo1() 中代码进行修改,使得其重复上锁

	void foo1() {
		m_mtx.lock();
		m_mtx.lock();
		std::cout << "foo1" << std::endl;
		m_mtx.unlock();
	}

单步调试运行结果:当程序运行至第二个锁处报异常崩溃
在这里插入图片描述
因此同一个线程无法重复多次进入mutex

3. 递归互斥量std::recursive_mutex

C++11考虑到同一线程重复使用互斥量的需求,提供了std::recursive_mutex允许互斥量的重复进入,但要注意释放问题,进入几次就需要释放几次。

以下代码,主线程进入std::recursive_mutex只释放一次:

//#include "stdafx.h"
#include <iostream>           // std::cout
#include <thread>             // std::thread
#include <mutex>              // std::mutex, std::unique_lock
#include <future>

using namespace std;

std::recursive_mutex g_mtx;

class CTest {
public:
	void foo1() {
		//引用计数
		g_mtx.lock();//+1
		g_mtx.lock();//+1
		g_mtx.lock();//+1
		std::cout << "foo1" << std::endl;
		g_mtx.unlock();//-1
	}

private:
};

void foo2() {
	g_mtx.lock();//+1
	std::cout << "foo2" << std::endl;
	g_mtx.unlock();//-1
}

int main()
{
	CTest t;

	t.foo1();

	std::thread thd(foo2);

	thd.join();

	return 0;
}

运行结果:由于主线程并未完全释放,子线程无法进入
在这里插入图片描述
使用建议:

  • 递归锁的递归是有计数器,超过了计数器最大值会失败,抛异常
  • 比非递归锁效率低
  • 递归进入占用递归锁,使得代码逻辑不清晰,引发其他问题。
    因此,建议酌情使用。

4. 超时互斥量std::timed_mutex

std::timed_mutex设置了等待超时的机制,之前的互斥量如果无法等待进入机会,会一直阻塞线程,使用std::timed_mutex可以为锁的等待设置一个超时值,一旦超时可以做其他事情。

timed_mutex比mutex主要是多了

  • try_lock 避免了阻塞,获取不到锁则直接返回false
  • try_lock_for() 尝试锁定互斥,若互斥在指定的时限时期中不可用则返回 等待一段时间
  • try_lock_until() 尝试锁定互斥,直至抵达指定时间点互斥不可用则返回 一个时间点

示例1:try_lock_for()

#include <thread>
#include <iostream>
#include <chrono>
#include <mutex>

std::timed_mutex test_mutex;

void f()
{
    auto now = std::chrono::steady_clock::now();
    //如使用test_mutex.try_lock尝试请求test_mutex锁,如果能够获得这个锁就可以进入,否则直接返回
    //此处是等一段时间
    if (test_mutex.try_lock_for(std::chrono::seconds(1))) {
        std::cout << "success!\n";

        test_mutex.unlock();
    } else {
        std::cout << "failed!\n";
    }

    std::cout << "hello world\n";
}

int main()
{
    std::lock_guard<std::timed_mutex> l(test_mutex);
    std::thread t(f);
    t.join();
}

示例2:try_lock_until()

//#include "stdafx.h"
#include <iostream>           // std::cout
#include <thread>             // std::thread
#include <mutex>              // std::mutex, std::unique_lock
#include <future>

using namespace std;

std::timed_mutex test_mutex;

void f()
{
	std::cout << "sub thread start\n";
	auto now = std::chrono::steady_clock::now();
	test_mutex.try_lock_until(now + std::chrono::seconds(5));
	std::cout << "sub thread end\n";
}

int main()
{
	std::cout << "main start\n";
	std::lock_guard<std::timed_mutex> l(test_mutex);
	std::thread t(f);
	t.join();
	std::cout << "main end\n";
}

5. 带超时的递归互斥量std::recursive_timed_mutex

主要结合了超时和递归。

6. 学习视频地址:互斥量recursive_mutex与timed_mutex的使用

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++新特性34_递归互斥量recursive_mutex与超时互斥量timed_mutex的使用(递归互斥量解决同一线程重复使用互斥量的需求;超时互斥量设置等待超时机制;解决互斥量阻塞问题) 的相关文章

  • 在模板类中声明模板友元类时出现编译器错误

    我一直在尝试实现我自己的链表类以用于教学目的 我在迭代器声明中指定了 List 类作为友元 但它似乎无法编译 这些是我使用过的 3 个类的接口 Node h define null Node
  • 机器Epsilon精度差异

    我正在尝试计算 C 中双精度数和浮点数的机器 epsilon 值 作为学校作业的一部分 我在 Windows 7 64 位中使用 Cygwin 代码如下 include
  • std::list 线程push_back、front、pop_front

    std list 线程安全吗 我假设不是这样 所以我添加了自己的同步机制 我认为我有正确的术语 但我仍然遇到问题 每个函数都由单独的线程调用 Thread1 不能等待 它必须尽可能快 std list
  • 随着时间的推移,添加到 List 变得非常慢

    我正在解析一个大约有 1000 行的 html 表 我从一个字符串中添加 10 个字符串 td 每行到一个list td
  • 从经典 ASP 调用 .Net C# DLL 方法

    我正在开发一个经典的 asp 项目 该项目需要将字符串发送到 DLL DLL 会将其序列化并发送到 Zebra 热敏打印机 我已经构建了我的 DLL 并使用它注册了regasm其次是 代码库这使得 IIS 能够识别它 虽然我可以设置我的对象
  • 用于 FTP 的文件系统观察器

    我怎样才能实现FileSystemWatcherFTP 位置 在 C 中 这个想法是 每当 FTP 位置添加任何内容时 我都希望将其复制到我的本地计算机 任何想法都会有所帮助 这是我之前问题的后续使用 NET 进行选择性 FTP 下载 ht
  • 访问外部窗口句柄

    我当前正在处理的程序有问题 这是由于 vista Windows 7 中增强的安全性引起的 特别是 UIPI 它阻止完整性级别较低的窗口与较高完整性级别的窗口 对话 就我而言 我想告诉具有高完整性级别的窗口进入我们的应用程序 它在 XP 或
  • WPF 数据绑定到复合类模式?

    我是第一次尝试 WPF 并且正在努力解决如何将控件绑定到使用其他对象的组合构建的类 例如 如果我有一个由两个单独的类组成的类 Comp 为了清楚起见 请注意省略的各种元素 class One int first int second cla
  • 重载 (c)begin/(c)end

    我试图超载 c begin c end类的函数 以便能够调用 C 11 基于范围的 for 循环 它在大多数情况下都有效 但我无法理解和解决其中一个问题 for auto const point fProjectData gt getPoi
  • ASP.NET Core 3.1登录后如何获取用户信息

    我试图在登录 ASP NET Core 3 1 后获取用户信息 如姓名 电子邮件 id 等信息 这是我在登录操作中的代码 var claims new List
  • 在 Unity 中实现 Fur with Shells 技术

    我正在尝试在 Unity 中实现皮毛贝壳技术 http developer download nvidia com SDK 10 5 direct3d Source Fur doc FurShellsAndFins pdf Fins 技术被
  • C# - 当代表执行异步任务时,我仍然需要 System.Threading 吗?

    由于我可以使用委托执行异步操作 我怀疑在我的应用程序中使用 System Threading 的机会很小 是否存在我无法避免 System Threading 的基本情况 只是我正处于学习阶段 例子 class Program public
  • C# xml序列化必填字段

    我需要将一些字段标记为需要写入 XML 文件 但没有成功 我有一个包含约 30 个属性的配置类 这就是为什么我不能像这样封装所有属性 public string SomeProp get return someProp set if som
  • LINQ:使用 INNER JOIN、Group 和 SUM

    我正在尝试使用 LINQ 执行以下 SQL 最接近的是执行交叉联接和总和计算 我知道必须有更好的方法来编写它 所以我向堆栈团队寻求帮助 SELECT T1 Column1 T1 Column2 SUM T3 Column1 AS Amoun
  • 复制目录下所有文件

    如何将一个目录中的所有内容复制到另一个目录而不循环遍历每个文件 你不能 两者都不Directory http msdn microsoft com en us library system io directory aspx nor Dir
  • 为什么 isnormal() 说一个值是正常的,而实际上不是?

    include
  • C# 使用“?” if else 语句设置值这叫什么

    嘿 我刚刚看到以下声明 return name null name NA 我只是想知道这在 NET 中叫什么 是吗 代表即然后执行此操作 这是一个俗称的 条件运算符 三元运算符 http en wikipedia org wiki Tern
  • Mono 应用程序在非阻塞套接字发送时冻结

    我在 debian 9 上的 mono 下运行一个服务器应用程序 大约有 1000 2000 个客户端连接 并且应用程序经常冻结 CPU 使用率达到 100 我执行 kill QUIT pid 来获取线程堆栈转储 但它总是卡在这个位置
  • 现代编译器是否优化乘以 1 和 -1

    如果我写 template
  • 使用 WGL 创建现代 OpenGL 上下文?

    我正在尝试使用 Windows 函数创建 OpenGL 上下文 现代版本 基本上代码就是 创建窗口类 注册班级 创建一个窗口 choose PIXELFORMATDESCRIPTOR并设置它 创建旧版 OpenGL 上下文 使上下文成为当前

随机推荐

  • eclipse中包里建包

    1 设置Package Presentation 为Hierarchical 最为关键一步 2 在src下新建一个名为com abc hrm的包 名字根据自己需要而定 3 在父包下新建子包a 4 继续在父包 com abc hrm a 下新
  • Java基础学习——Java线程(二)同步代码块、同步方法、Lock锁、死锁程序例子、不同类型的锁

    对于之前买票的练习 又出现多个10张票的情况 这里对这一现象进行分析 对于代码 for int i 1 i lt 100 i if ticketNum gt 0 System out println 我在 this getName 买到了第
  • vue - Vue介绍

    一 初始化Vue脚手架 1 说明 一般脚手架选择最新版本 2 具体步骤 全局安装vue cli脚手架 切换到项目目录 运行 vue create 加一个非主流库的名字 即可创建一个vue项目 运行 npm run serve 将项目在服务器
  • 跳跃线性链表容器

    此容器用于将ArrayList与LinkedList进行结合 利于容纳大量数据之后对容器的中间段进行增删 一般而言 ArrayList的性能总是快于LinkedList 只在容纳大量数据后 对容器的起始区域进行增删时 LinkedList才
  • 浙江大学提出自感知IMU网络精准捕获3D变形

    运动捕捉目前有两种主流方法 视觉捕捉能捕获复杂的三维几何变形 但依赖于昂贵的光学设备并且存在视线遮挡问题 基于IMU的方法虽然简便 但难以捕获细微的3D变形 为了解决这个问题 浙江大学的研究者们提出了一种可配置的自感知IMU传感器网络 解决
  • Rabbitmq入门到进阶看这篇就够了!

    安装前提 安装 erlang windows用户名非中文 可以关注我的公众号 知识追寻者 回复 rabbitmq 获取已经下载好的安装包和配套源码地址 本套教程对应知识追寻者网址 windows安装rabbitmq zszxz com Ra
  • 【IEEE】2022年第四届欧亚计算机科学与信息技术国际会议(FCSIT 2022)

    2022年第四届欧亚计算机科学与信息技术国际会议 FCSIT 2022 重要信息 会议网址 www ecfcsit org 会议时间 2022年12月16 18日 召开地点 中国北京 出版社 IEEE CPS 截稿时间 2022年10月31
  • mqtt.js

    什么是MQTT协议 MQTT Message Queuing Telemetry Transport 消息队列遥测传输协议 是一种基于发布 订阅 publish subscribe 模式的 轻量级 通讯协议 该协议构建于TCP IP协议上
  • [Hadoop] start-dfs.sh ssh报错

    Permission denied publickey 决解方案 相关命令 cd ssh ssh keygen t rsa p cat id rsa pub gt gt authorized keys chmod 0600 authoriz
  • yml基本语法

    1 基本语法 格式要求 k 空格 v 表示一对键值对 空格必须有 以空格的缩进来控制层级关系 只要是左对齐的一列数据 都是同一个层级的 server port 8081 path hello 1 2 3 属性和值也是大小写敏感 2 值的写法
  • R语言绘制PCA双标图、碎石图、变量载荷图和变量贡献图

    1 原论文数据双标图 代码 setwd D Desktop 0000 R 更改路径 导入数据 df lt read table Input data csv header T sep 所需的包 packages lt c ggplot2 t
  • java entityframework,entity-framework – 实体框架核心DbContext和依赖注入

    您可以通过构造函数注入将dbcontext从数据访问层添加到类中来解决此问题 public class Startup public void ConfigureServices IServiceCollection services se
  • Flex布局--骰子布局

    Flex布局 骰子布局 1点骰子 html css box1 width 100px height 100px border 1px solid pink margin right 3px background color ffffff d
  • 2.4g 无线通讯至服务器,WiFi、2.4G、433M、GPRS无线通讯方式的区别

    原标题 WiFi 2 4G 433M GPRS无线通讯方式的区别 WiFi 2 4G 433M GPRS是目前深圳信立重点推荐的且比较常用的无线通讯方式 被大量应用于供排水管网 热力管网 农业大棚 养殖场 馆藏仓库 储罐 实验室 工厂车间
  • 判断字符串非空if(str!=null && str!=""){}

    熟手判断字符串非空一般都会做两次判断 if str null str 或者 if str null str length 0 或者 if str null str equals 为什么要这么麻烦呢 相信大家都遇到过空指针报错的情况 java
  • python异常模块raise的概念以及基本用法

    当程序出现错误 python会自动引发异常 也可以通过raise显示地引发异常 一旦执行了raise语句 raise后面的语句将不能执行 raise 用raise语句来引发一个异常 异常 错误对象必须有一个名字 且它们应是Error或Exc
  • 多视图综述以及图像检索

    1 1 算法分类 1 1 1 协同训练 该方法旨在最大限度地扩展所有观点的相互协议 并达成最广泛的共识 协同训练算法一般过程如图1所示 根据该过程对算法进行交替训练 利用先验信息或相互学习知识 使两种不同视图的一致性最大化 Co train
  • 秦九韶算法详解

    秦九韶算法 秦九韶算法是将一元n次多项式的求值问题转化为n个一次式的算法 比普通计算方式提高了一个数量级 普通算式 a x i 因为多次求幂 消耗了大量的计算时间 我们来分析一下秦九韶算法 例如 求 1 x 2x 2 3x 3 当x 2时的
  • MongoDB 数据库(一):MongoDB的介绍与安装

    目录 一 MongoDB数据库的介绍与安装 1 1 NoSQL数据库简介 1 2 MongoDB 简介 1 2 1 再议业务应用场景 1 2 2 为什么要使用 MongoDB 1 2 3 适用场景 二 安装和使用MongoDB客户端 2 1
  • C++新特性34_递归互斥量recursive_mutex与超时互斥量timed_mutex的使用(递归互斥量解决同一线程重复使用互斥量的需求;超时互斥量设置等待超时机制;解决互斥量阻塞问题)

    接上篇C 新特性33 死锁产生的原因及避免 线程在等待一个永远都不能成功的条件成立 从而进入到陷入休眠 永远不能被唤醒的状态 通过调整锁的使用顺序解决死锁问题 本篇将会学习互斥体的相关知识 C 新特性34 递归互斥量recursive mu