C++多线程学习(三):锁资源管理和条件变量
参考引用
- C++11 14 17 20 多线程从原理到线程池实战
- 代码运行环境:Visual Studio 2019
1. 利用栈特性自动释放锁 RAII
1.1 什么是 RAII
- RAII (Resource Acquisition Is Initialization):使用局部对象来管理资源的技术称为资源获取即初始化
- 它的生命周期是由操作系统来管理,无需人工介入
- 资源的销毁容易忘记,造成死锁或内存泄漏
1.2 手动实现 RAII 管理 mutex 资源
-
thread_RAII.cpp
#include <iostream> #include <thread> #include <string> #include <mutex> using namespace std; // RAII class XMutex { public: // 在构造函数中锁住,一生成对象 mux 就拿到锁 XMutex(mutex &mux) : mux_(mux) { cout << "Lock" << endl; mux.lock(); } // 析构函数中释放 ~XMutex() { cout << "Unlock" << endl; mux_.unlock(); } private: // 引用方式存储锁,引用必须在初始化时就要赋值 mutex& mux_; }; static mutex mux; void TextMutex(int status) { XMutex lock(mux); // 不需要关心锁的 unlock() 释放 if (status == 1) { cout << " = 1" << endl; return; } else { cout << " != 1" << endl; return; } } // 超出这个大括号后,会调用析构函数释放栈中资源 int main(int argc, char* argv[]) { TextMutex(1); TextMutex(2); getchar(); return 0; }
-
控制台输出
Lock = 1 Unlock Lock != 1 Unlock
2. lock_guard:C++11 支持的 RAII 管理互斥资源
-
C++11 实现严格基于作用域的互斥体所有权包装器
-
adopt_lock:C++11 类型为 adopt_lock_t,假设调用方已拥有互斥的所有权
-
通过 {} 控制锁的临界区(栈区间),出了 {} 后自动释放锁资源
-
thread_RAII2.cpp
#include <thread> #include <iostream> #include <string> #include <mutex> using namespace std; static mutex gmutex; void TestLockGuard(int i) { gmutex.lock(); { // 已经拥有锁,不锁定,退出解锁 lock_guard<mutex> lock(gmutex, adopt_lock); // 结束释放锁 } { lock_guard<mutex> lock(gmutex); cout << "begin thread " << i << endl; } for (;;) { { lock_guard<mutex> lock(gmutex); cout << "In " << i << endl; } this_thread::sleep_for(500ms); } } int main(int argc, char* argv[]) { for (int i = 0; i < 3; i++) { thread th(TestLockGuard, i + 1); th.detach(); } getchar(); return 0; }
-
控制台输出
begin thread 1 In 1 begin thread 3 In 3 begin thread 2 In 2 In 1 In 2 In 3 In 1 ...
3. unique_lock:C++11 实现可移动的互斥体所有权包装器
-
支持临时释放锁 unlock
-
支持 adopt_lock:(已经拥有锁,不加锁,出栈区会释放)
-
支持 defer_lock:(延后拥有,不加锁,出栈区不释放)
-
支持 try_to_lock:尝试获得互斥的所有权而不阻塞,获取失败退出栈区不会释放,通过 owns_lock() 函数判断
-
thread_RAII3.cpp
#include <thread> #include <iostream> #include <string> #include <mutex> using namespace std; int main(int argc, char* argv[]) { { static mutex mux; { unique_lock<mutex> lock(mux); lock.unlock(); // 临时释放锁 lock.lock(); } { // 已经拥有锁 不锁定,退出栈区解锁 mux.lock(); unique_lock<mutex> lock(mux, adopt_lock); } { // 延后加锁 不拥有 退出栈区不解锁 unique_lock<mutex> lock(mux, defer_lock); // 加锁 退出栈区解锁 lock.lock(); } { //mux.lock(); // 尝试加锁 不阻塞 失败不拥有锁 unique_lock<mutex> lock(mux, try_to_lock); if (lock.owns_lock()) { cout << "owns_lock" << endl; } else { cout << "not owns_lock" << endl; } } } getchar(); return 0; }
4. shared_lock C++14 实现可移动的共享互斥体所有权封装器
int main(int argc, char* argv[]) {
{
// 共享锁
static shared_timed_mutex tmux;
// 读取锁--共享锁
{
// 调用共享锁
shared_lock<shared_timed_mutex> lock(tmux);
cout << "read data" << endl;
// 退出栈区 释放共享锁
}
// 写入锁--互斥锁
{
unique_lock<shared_timed_mutex> lock(tmux);
cout << "write data" << endl;
}
}
}