C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > c++ 递归锁

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

作者:却道天凉_好个秋

这篇文章主要介绍了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下递归锁

特点

// 初始化一个临界区对象
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++ 递归锁的使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

阅读全文