c++ 递归锁的使用示例代码

 更新时间:2023年08月10日 14:18:28   作者:却道天凉_好个秋  
这篇文章主要介绍了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 thread
	std::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 threads
  Id   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 thread1
	std::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++ 递归锁的使用的文章就介绍到这了,更多相关c++ 递归锁的使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C/C++产生随机数函数简单介绍

    C/C++产生随机数函数简单介绍

    这篇文章主要为大家详细介绍了C/C++产生随机数函数的实现方法,如何使用C/C++产生随机数函数,感兴趣的小伙伴们可以参考一下
    2016-04-04
  • C++语言实现线性表之链表实例

    C++语言实现线性表之链表实例

    这篇文章主要介绍了C++语言实现线性表之链表,实例分析了C++实现线性表中链表的原理与相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-04-04
  • 简要对比C语言中三个用于退出进程的函数

    简要对比C语言中三个用于退出进程的函数

    这篇文章主要介绍了C语言中三个用于退出进程的函数的对比,分别为_exit()函数和on_exit()函数以及atexit()函数,需要的朋友可以参考下
    2015-08-08
  • C语言浅析函数的用法

    C语言浅析函数的用法

    C语言函数是用来模块化构建程序的。如果你的功能少,你可以全都写在mian函数中,但是当实现功能多的时候,如果全写在main的函数里,不仅代码不美观,而且函数实现的时候结构复杂,代码重复
    2022-07-07
  • 在Visual Studio 2019中修改项目名的方法

    在Visual Studio 2019中修改项目名的方法

    这篇文章主要介绍了在Visual Studio 2019中修改项目名的方法,文中通过示例介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • ReSharper 的安装使用详细教程

    ReSharper 的安装使用详细教程

    resharper安装教程是关于vs2012一个非常好用的插件的安装教程,建议大家尝试安装,今天通过本教程帮助大家学习ReSharper 的安装使用详细教程,感兴趣的朋友一起看看吧
    2021-06-06
  • C++ Qt属性系统详细介绍

    C++ Qt属性系统详细介绍

    这篇文章主要介绍了C++ Qt属性系统详细介绍的相关资料,需要的朋友可以参考下
    2016-12-12
  • C++存储链接性原理详解

    C++存储链接性原理详解

    这篇文章主要为大家介绍了C++存储链接性原理详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • 使用C++制作简单的web服务器(续)

    使用C++制作简单的web服务器(续)

    本文承接上文《使用C++制作简单的web服务器》,把web服务器做的功能稍微强大些,主要增加的功能是从文件中读取网页并返回给客户端,而不是把网页代码写死在代码中,有需要的小伙伴来参考下吧。
    2015-03-03
  • C/C++中一次性执行多个DOS命令的实现思路

    C/C++中一次性执行多个DOS命令的实现思路

    在C语言中执行DOS命令的方法很多,在这就不一给大家一一介绍了,本文重点给大家介绍C/C++中一次性执行多个DOS命令的实现思路,需要的朋友参考下
    2017-12-12

最新评论