c++ 递归锁的使用
非递归锁
同一个线程里,在锁未释放的情况下反复加锁,会导致死锁。
- 示例
#include <iostream>
#include <mutex>
#include <thread>
#include <unistd.h>
using namespace std;std::mutex m_mutex;void Func()
{m_mutex.lock();cout << "Func" << endl;m_mutex.unlock();
}int main()
{// create threadstd::thread th1 = std::thread([&]() {while(1){m_mutex.lock();cout << "thread1 working" << endl;Func();m_mutex.unlock();sleep(1);}});th1.join(); while(1){sleep(2);}return 0;
}
- 运行
[root@localhost ~]# ./testDeadLock
thread1 working
发现程序卡住不动,无Func函数中的打印。
- 调试
[root@localhost deadLock]# ps -aux | grep testDeadLock
root 88473 0.0 0.1 27200 1156 pts/1 Sl+ 14:13 0:00 ./testDeadLock
root 88541 0.0 0.1 112832 996 pts/2 R+ 14:13 0:00 grep --color=auto testDeadLock
[root@localhost deadLock]# gdb attach 88473
//...
(gdb) info threadsId Target Id Frame 2 Thread 0x7f13e4603700 (LWP 88474) "testDeadLock" 0x00007f13e530454d in __lll_lock_wait () from /lib64/libpthread.so.0
* 1 Thread 0x7f13e5a1d740 (LWP 88473) "testDeadLock" 0x00007f13e52ff017 in pthread_join () from /lib64/libpthread.so.0
(gdb) t 2
[Switching to thread 2 (Thread 0x7f13e4603700 (LWP 88474))]
#0 0x00007f13e530454d in __lll_lock_wait () from /lib64/libpthread.so.0
(gdb) bt
#0 0x00007f13e530454d in __lll_lock_wait () from /lib64/libpthread.so.0
#1 0x00007f13e52ffe9b in _L_lock_883 () from /lib64/libpthread.so.0
#2 0x00007f13e52ffd68 in pthread_mutex_lock () from /lib64/libpthread.so.0
#3 0x0000000000402534 in __gthread_mutex_lock (__mutex=0x604120 <m_mutex>) at /opt/rh/devtoolset-8/root/usr/include/c++/8/x86_64-redhat-linux/bits/gthr-default.h:748
#4 0x0000000000402584 in std::mutex::lock (this=0x604120 <m_mutex>) at /opt/rh/devtoolset-8/root/usr/include/c++/8/bits/std_mutex.h:103
#5 0x0000000000401f88 in Func () at source/test.cpp:12
#6 0x000000000040200a in <lambda()>::operator()(void) const (__closure=0x2439018) at source/test.cpp:28
#7 0x0000000000402242 in std::__invoke_impl<void, main()::<lambda()> >(std::__invoke_other, <unknown type in /home/testDeadLock, CU 0x0, DIE 0xada9>) (__f=<unknown type in /home/testDeadLock, CU 0x0, DIE 0xada9>) at /opt/rh/devtoolset-8/root/usr/include/c++/8/bits/invoke.h:60
#8 0x000000000040209e in std::__invoke<main()::<lambda()> >(<unknown type in /mnt/hgfs/test/deadLock/debug.x64-linux-g8/testDeadLock, CU 0x0, DIE 0xb073>) (__fn=<unknown type in /home/testDeadLock, CU 0x0, DIE 0xb073>) at /opt/rh/devtoolset-8/root/usr/include/c++/8/bits/invoke.h:95
#9 0x0000000000402484 in std::thread::_Invoker<std::tuple<main()::<lambda()> > >::_M_invoke<0>(std::_Index_tuple<0>) (this=0x2439018) at /opt/rh/devtoolset-8/root/usr/include/c++/8/thread:244
#10 0x000000000040245a in std::thread::_Invoker<std::tuple<main()::<lambda()> > >::operator()(void) (this=0x2439018) at /opt/rh/devtoolset-8/root/usr/include/c++/8/thread:253
#11 0x000000000040243e in std::thread::_State_impl<std::thread::_Invoker<std::tuple<main()::<lambda()> > > >::_M_run(void) (this=0x2439010) at /opt/rh/devtoolset-8/root/usr/include/c++/8/thread:196
#12 0x00000000004028ff in execute_native_thread_routine ()
#13 0x00007f13e52fdea5 in start_thread () from /lib64/libpthread.so.0
#14 0x00007f13e4702b0d in clone () from /lib64/libc.so.6
(gdb) f 5
#5 0x0000000000401f88 in Func () at source/test.cpp:12
12 m_mutex.lock();
(gdb) p *(pthread_mutex_t*)$rdi
$1 = {__data = {__lock = 2, __count = 0, __owner = 88474, __nusers = 1, __kind = 0, __spins = 0, __elision = 0, __list = {__prev = 0x0, __next = 0x0}}, __size = "\002\000\000\000\000\000\000\000\232Y\001\000\001", '\000' <repeats 26 times>, __align = 2}
(gdb)
- 排查步骤
1) ps查看进程id;2) "gdb attach 进程id"附加至该进程;3) "info threads"查看所有线程信息;4) 查找有执行锁等待__lll_lock_wait ()的线程, 一般为死锁线程, 切换至该线程, 如切换至线程2,则执行"t 2";5) "bt" 查看当前线程堆栈;6) "f 帧数"切换至自己所写代码处;7) "p *(pthread_mutex_t*)$rdi"打印寄存器信息, rdi为显示寄存器;8) 对7)的打印主要关注两个地方,"__lock = 2"一般说明有死锁, "__owner = 88474"代码发生死锁的线程, 与"info threads"的打印信息中 "(LWP 88474)"对应, 接下来直接分析88474指向的线程即可;
此排查方式适用于多个线程出现死锁的情况。
递归锁
递归锁允许同一个线程在未释放其拥有的锁时反复对该锁进行加锁操作。
- 示例
在c++11中,std::recursive_mutex 来支持递归锁。
#include <iostream>
#include <mutex>
#include <thread>
#include <unistd.h>
using namespace std;std::recursive_mutex m_recursive_mutex;void Func()
{std::lock_guard<std::recursive_mutex> mtx(m_recursive_mutex);cout << "Func" << endl;
}int main()
{// create thread1std::thread th1 = std::thread([&]() {while(1){std::lock_guard<std::recursive_mutex> mtx(m_recursive_mutex);cout << "thread1 working" << endl;Func();sleep(1);}});th1.join(); while(1){sleep(2);}return 0;
}
- 运行
[root@localhost ~]# ./testDeadLock
thread1 working
Func
thread1 working
Func
thread1 working
Func
thread1 working
Func
程序可正常打印。
windows下递归锁
- 特点
- windows下的互斥量和临界区(关键段)默认支持递归锁;
- EnterCriticalSection可以被多次调用;
- EnterCriticalSection与LeaveCriticalSection调用次数必须对应;
- 临界区函数如下:
// 初始化一个临界区对象
void InitializeCriticalSection( LPCRITICAL_SECTION lpCriticalSection);// 删除临界区对象释放由该对象使用的所有系统资源
void DeleteCriticalSection(_Inout_ LPCRITICAL_SECTION lpCriticalSection);// 进入临界区
void EnterCriticalSection( LPCRITICAL_SECTION lpCriticalSection );// 删除临界区
void LeaveCriticalSection( LPCRITICAL_SECTION lpCriticalSection );
- 示例
#include <iostream>
#include <thread>
#include <Windows.h>
using namespace std;CRITICAL_SECTION g_Critical;class CWinRecursiveLock
{
public:CWinRecursiveLock(CRITICAL_SECTION *pCritcal) {m_pCritical = pCritcal;EnterCriticalSection(m_pCritical);}~CWinRecursiveLock() //析构函数{LeaveCriticalSection(m_pCritical);}private:CRITICAL_SECTION *m_pCritical = nullptr;
};void Func()
{CWinRecursiveLock wlock(&g_Critical); // 重复加锁cout << "Func" << endl;
}int main()
{// 初始化InitializeCriticalSection(&g_Critical);std::thread th1 = std::thread([&]() {while(1){CWinRecursiveLock wlock(&g_Critical);cout << "thread1 working" << endl;Func();Sleep(1000);}});th1.join(); system("pause");return 0;
}
经测试,程序可正常运行。
相关文章:
c++ 递归锁的使用
非递归锁 同一个线程里,在锁未释放的情况下反复加锁,会导致死锁。 示例 #include <iostream> #include <mutex> #include <thread> #include <unistd.h> using namespace std;std::mutex m_mutex;void Func() {m_mutex.lock(…...
Oracle TDE wallet
1. 钱夹密码千万不能忘记,这也是使用TDE 需要承担的风险。 2. 只要将wallet cwallet.sso 拷贝过去,加密没有意义! 钱夹的备份 正如上述,已经加密过的表列或者表空间,钱夹必须打开才能够查询到里面的数据。如果钱夹丢…...

多模态学习
一、目标 三、多模态核心任务 题目:...

Android学习之路(2) 文本设置
Android学习之路(1) 文本 一、设置文本内容 设置文本内容的两种方式: 一种是在XML文件中通过属性android:text设置文本代码如下 <TextViewandroid:id"id/tv_hello"android:layout_width"wrap_content"android:layout_height"wrap_c…...

手写springboot
前言 首先确定springboot在spring基础上主要做了哪些改动:内嵌tomcatspi技术动态加载 一、基本实现 1. 建一个工程目录结构如下: springboot: 源码实现逻辑 user : 业务系统2.springboot工程项目构建 1. pom依赖如下 <dependencies>…...

报错Uncaught (in promise) Error: Manifest request to...
在使用nuxt框架时,出现如下报错: 解决方案: 不要打开两个以上的开发者工具更换nuxt的端口号 参考资料:https://github.com/nuxt/nuxt.js/issues/6202...

微信私域更好玩了
之前分享过,“小绿书”“公众号文章转音频”等内测中或悄悄已升级的功能。 其实,微信还在内测很多新功能,只是没公开 今天,小编又发现新升级 就是『附近』功能 增加了一个本地生活的入口,这里面是短视频和图文 展示…...
基于ant-design的a-modal自定义vue拖拽指令
写一个dragDialog.js 在main.js中引入 import ‘./core/directives/dragDialog.js’ // 让 dialog 支持鼠标拖动 import Vue from vueVue.directive(DragDialog, {update: function (el, binding, vnode) {if (!binding.value || !binding.value.reset) returnconst dialog e…...
【ES】笔记-模板字符串(template string)是增强版的字符串`${expresions}`
模板字符串 传统的 JavaScript 语言,输出模板通常是这样写的(下面使用了 jQuery 的方法)。 $(#result).append(There are <b> basket.count </b> items in your basket, <em> basket.onSale </em> are on sal…...

利用 OLE 对象漏洞的 HWP 恶意文件浮出水面
ASEC 分析人员发现了一个利用 OLE 对象的恶意 HWP 文件,尽管其使用了 2020 年就被识别的恶意 URL,但仍然使用了 Flash 漏洞(CVE-2018-15982),需要用户谨慎对待。 打开 HWP 文件时会在 %TEMP%文件夹中生成如下文件。攻…...

【CSS】倾斜按钮
效果 index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"/><meta http-equiv"X-UA-Compatible" content"IEedge"/><meta name"viewport" content"widthdevice-…...

js 正则表达式
js 正则表达式 http://tool.oschina.net/regex https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions 11 22...

心理咨询预约管理系统javaweb医院挂号jsp源代码mysql
本项目为前几天收费帮学妹做的一个项目,Java EE JSP项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。 一、项目描述 心理咨询预约管理系统javaweb MVC模式,普…...

Linux中安装Node
安装 先从 官方网站 下载安装包,有时 node 版本太新会导致失败,详见下方的常见问题第2点 cd /home // 创建目录,将下载好的 node 安装包上传到此目录 mkdir Download mkdir /usr/local/lib/node解压 // 解压,前面是文件当前路径…...

爬虫011_元组高级操作_以及字符串的切片操作---python工作笔记030
获取元组的下标对应的值 注意元组是不可以修改值的,只能获取不能修改 但是列表是可以修改值的对吧...

JVM虚拟机篇
JVM组成 面试题1:什么是程序计数器? 面试题2:你能给我详细的介绍Java堆吗? 面试题3:什么是虚拟机栈? 面试题4:垃圾回收是否涉及栈内存? 垃圾回收主要指就是堆内存,当栈帧弹栈以后…...

Flutter 让软键盘不再自动弹起
1、问题说明: 在开发中,经常遇到这种事,一个页面有输入框,点击输入框后,会弹起软键盘,同时输入框会聚焦,手动收起软键盘后,点击另一个按钮前往下一个页面或者显示一个弹窗࿰…...

k8s 自身原理 1
咱们从 pod 一直分享到最近的 Statefulset 资源,到现在好像我们只是知道如何使用 k8s,如何按照 k8s 设计好的规则去应用,去玩 k8s 仔细想想,对于 k8s 自身的内在原理,我们好像还不是很清楚,对于每一个资源…...
在CPU上安装部署chatglm-6b实用经验分享
chatglm-6b很强,很多同学都想自己试一试,但不是每个人都有GPU、高端显卡的环境,大多数同学都是一台普通的笔记本。 笔者这里分享一下在自己的8G内存,intel i3笔记本上安装部署chatglm-6b的实际经验。有很多网站都分享了一些经验&…...

Mermaid系列之FlowChart流程图
一.欢迎来到我的酒馆 介绍mermaid下,Flowchat流程图语法。 目录 一.欢迎来到我的酒馆二.什么是mermiad工具三.在vs code中使用mermaid四.基本语法 二.什么是mermiad工具 2.1 mermaid可以让你使用代码来创建图表和可视化效果。mermaid是一款基于javascript语言的图表…...

智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...