C++ std::Recursive_mutex 支持 “對同一互斥量進行嵌套加鎖”


使用場景:一個類的不同成員函數之間,存在相互調用的情況, 如果這樣的成員函數作為線程的入口函數時,就會出現在成員函數 func1()中對某個互斥量上鎖,並且, func1()中調用了成員函數 func2() ,實際上 func2()為了保護成員數據,func2()內部也對同一個互斥量上鎖。 在我們對 std::mutex 的使用經驗中, 這樣的情況,必定會導致未定義的行為,從而導致死鎖的產生。

 

C++標准庫為此提供了 std::recursive_mutex 互斥量, 它在具備 std::mutex 的功能之上, 還可以可以支持上面描述的  “對同一個互斥量進行嵌套上鎖” 的能力。

注意:這個 “嵌套鎖”的能力只是在同一線程中, 多個線程間還是保持與 std::mutex 一致的互斥同步能力。

下面分別貼出成員函數存在嵌套調用時 std::recursive_mutex 比 std::mutex 超強的表現能力。

 1 #include <thread>
 2 #include <iostream>
 3 #include <mutex>
 4 #include <chrono>
 5 
 6 class Try_Recursive_Mutex
 7 {
 8     std::mutex   mtx;
 9     std::recursive_mutex recur_mtx;
10     std::chrono::milliseconds sleep_time = std::chrono::milliseconds(1000);
11 public:
12     Try_Recursive_Mutex();
13 
14     void fun1(){
15         std::lock_guard<std::recursive_mutex> lkgd( recur_mtx );
16         std::cout<<__FUNCTION__<<"---thread id: "<<std::this_thread::get_id()<<"---"<<std::endl;
17         std::this_thread::sleep_for(sleep_time);
18         fun2();
19     }
20 
21     void fun2(){
22         std::lock_guard<std::recursive_mutex> lkgd( recur_mtx );
23         std::cout<<__FUNCTION__<<"---thread id: "<<std::this_thread::get_id()<<"---"<<std::endl;
24         std::this_thread::sleep_for(sleep_time);
25         fun3();
26     }
27 
28     void fun3(){
29         std::lock_guard<std::recursive_mutex> lkgd( recur_mtx );
30         std::cout<<__FUNCTION__<<"---thread id: "<<std::this_thread::get_id()<<"---"<<std::endl;
31         std::this_thread::sleep_for(sleep_time);
32     }
33 };

 

 1 #include "Try_Recursive_Mutex.h"
 2 #include <QApplication>
 3 
 4 int main()
 5 {
 6     Try_Recursive_Mutex trm;
 7     std::thread th_1(&Try_Recursive_Mutex::fun1, &trm);
 8     std::thread th_2(&Try_Recursive_Mutex::fun1, &trm);
 9     std::thread th_3(&Try_Recursive_Mutex::fun1, &trm);
10     th_1.join();
11     th_2.join();
12     th_3.join();
13     return 0;
14 }

 

運行結果如下:

16:24:34: Starting D:\a_zhm\StudyCode\threadStudy\14_protect_unNormalUpdate_data\build-protect_unNormalUpdate_data-Desktop_Qt_5_9_8_MSVC2015_64bit-Debug\debug\protect_unNormalUpdate_data.exe...

Try_Recursive_Mutex::fun1---thread id: 13484---

Try_Recursive_Mutex::fun2---thread id: 13484---

Try_Recursive_Mutex::fun3---thread id: 13484---

Try_Recursive_Mutex::fun1---thread id: 8224---

Try_Recursive_Mutex::fun2---thread id: 8224---

Try_Recursive_Mutex::fun3---thread id: 8224---

Try_Recursive_Mutex::fun1---thread id: 528---

Try_Recursive_Mutex::fun2---thread id: 528---

Try_Recursive_Mutex::fun3---thread id: 528---

16:24:43: D:/a_zhm/StudyCode/threadStudy/14_protect_unNormalUpdate_data/build-protect_unNormalUpdate_data-Desktop_Qt_5_9_8_MSVC2015_64bit-Debug/debug/protect_unNormalUpdate_data.exe exited with code 0

 

同樣的情況,我們使用傳統的  std::mutex 來實現,就會出現未定義行為,產生死鎖而導致程序崩潰:

 1 #include <thread>
 2 #include <iostream>
 3 #include <mutex>
 4 #include <chrono>
 5 
 6 class Try_Recursive_Mutex
 7 {
 8     std::mutex   mtx;
 9     std::recursive_mutex recur_mtx;
10     std::chrono::milliseconds sleep_time = std::chrono::milliseconds(1000);
11 public:
12     Try_Recursive_Mutex();
13 
14     void fun1(){
15         std::lock_guard<std::mutex> lkgd( mtx );
16         std::cout<<__FUNCTION__<<"---thread id: "<<std::this_thread::get_id()<<"---"<<std::endl;
17         std::this_thread::sleep_for(sleep_time);
18         fun2();
19     }
20 
21     void fun2(){
22         std::lock_guard<std::mutex> lkgd( mtx );
23         std::cout<<__FUNCTION__<<"---thread id: "<<std::this_thread::get_id()<<"---"<<std::endl;
24         std::this_thread::sleep_for(sleep_time);
25         fun3();
26     }
27 
28     void fun3(){
29         std::lock_guard<std::mutex> lkgd( mtx );
30         std::cout<<__FUNCTION__<<"---thread id: "<<std::this_thread::get_id()<<"---"<<std::endl;
31         std::this_thread::sleep_for(sleep_time);
32     }
33 };

 

程序的運行情況如下:

 

 

 

總結: 新科技 std::recursive_mutex 就是好用!!! 特定場合,我們就選用特殊的技術。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM