c++ 遞歸鎖的使用示例代碼
非遞歸鎖
同一個線程里,在鎖未釋放的情況下反復(fù)加鎖,會導(dǎo)致死鎖。
示例
#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;
}運(yùn)行
[root@localhost ~]# ./testDeadLock thread1 working
發(fā)現(xiàn)程序卡住不動,無Func函數(shù)中的打印。
調(diào)試
[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查看進(jìn)程id; 2) "gdb attach 進(jìn)程id"附加至該進(jìn)程; 3) "info threads"查看所有線程信息; 4) 查找有執(zhí)行鎖等待__lll_lock_wait ()的線程, 一般為死鎖線程, 切換至該線程, 如切換至線程2,則執(zhí)行"t 2"; 5) "bt" 查看當(dāng)前線程堆棧; 6) "f 幀數(shù)"切換至自己所寫代碼處; 7) "p *(pthread_mutex_t*)$rdi"打印寄存器信息, rdi為顯示寄存器; 8) 對7)的打印主要關(guān)注兩個地方,"__lock = 2"一般說明有死鎖, "__owner = 88474"代碼發(fā)生死鎖的線程, 與"info threads"的打印信息中 "(LWP 88474)"對應(yīng), 接下來直接分析88474指向的線程即可;
此排查方式適用于多個線程出現(xiàn)死鎖的情況。
遞歸鎖
遞歸鎖允許同一個線程在未釋放其擁有的鎖時(shí)反復(fù)對該鎖進(jìn)行加鎖操作。
示例
在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;
}運(yùn)行
[root@localhost ~]# ./testDeadLock
thread1 working
Func
thread1 working
Func
thread1 working
Func
thread1 working
Func
程序可正常打印。
windows下遞歸鎖
特點(diǎn)
- windows下的互斥量和臨界區(qū)(關(guān)鍵段)默認(rèn)支持遞歸鎖;
- EnterCriticalSection可以被多次調(diào)用;
- EnterCriticalSection與LeaveCriticalSection調(diào)用次數(shù)必須對應(yīng);
- 臨界區(qū)函數(shù)如下:
// 初始化一個臨界區(qū)對象 void InitializeCriticalSection( LPCRITICAL_SECTION lpCriticalSection); // 刪除臨界區(qū)對象釋放由該對象使用的所有系統(tǒng)資源 void DeleteCriticalSection(_Inout_ LPCRITICAL_SECTION lpCriticalSection); // 進(jìn)入臨界區(qū) void EnterCriticalSection( LPCRITICAL_SECTION lpCriticalSection ); // 刪除臨界區(qū) 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() //析構(gòu)函數(shù)
{
LeaveCriticalSection(m_pCritical);
}
private:
CRITICAL_SECTION *m_pCritical = nullptr;
};
void Func()
{
CWinRecursiveLock wlock(&g_Critical); // 重復(fù)加鎖
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;
}經(jīng)測試,程序可正常運(yùn)行。
到此這篇關(guān)于c++ 遞歸鎖的使用的文章就介紹到這了,更多相關(guān)c++ 遞歸鎖的使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
最短時(shí)間學(xué)會基于C++實(shí)現(xiàn)DFS深度優(yōu)先搜索
常見使用深度優(yōu)先搜索(DFS)以及廣度優(yōu)先搜索(BFS)這兩種搜索,今天我們就來講講什么是深度優(yōu)先搜索,感興趣的可以了解一下2021-08-08
C語言與C++動態(tài)通訊錄超詳細(xì)實(shí)現(xiàn)流程
這篇文章主要為大家介紹了C語言與C++動態(tài)實(shí)現(xiàn)通訊錄,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-05-05

