# lock_guard,unique_lock和shared_lock
# lock_guard
std::lock_guard
是一个轻量级的互斥锁封装,基于std::mutex
实现。- 基于C++
RAII (Resource Acquisition Is Initialization)
实现,在构造时加锁,在析构时解锁 - 适用于简单的互斥操作,例如在有限的作用域内加锁和解锁。
- 不能手动解锁,只能在作用域结束时自动解锁。
# unique_lock
std::unique_lock
是一个更灵活的互斥锁封装,也基于std::mutex
实现。- 可以在构造时选择是否立即加锁,也可以在任意时刻手动解锁。
- 可以传递不同作用域中互斥量的所有权。
- 支持更多高级功能,例如超时、条件变量等。
- 析构时会根据当前锁的状态自动决定是否解锁。
# std::shared_lock
std::shared_lock
是c++17
中引入的共享锁std::shared_lock
是一个更灵活的互斥锁封装,也基于std::mutex
实现,专为共享互斥锁而设计,支持多个读取器。- 可以在构造时选择是否立即加锁,也可以在任意时刻手动解锁
- 适用于共享互斥锁的场景,允许多个线程同时持有共享锁,以读取相同的数据。
- 与
std::lock_guard
类似,它不支持手动解锁或重新锁定 - 如果有线程需要写入数据,它必须使用独占锁(
std::unique_lock
)来获取写入权限。
# 使用场景
- 只需要简单的加锁和解锁,且作用域较小,可以使用
std::lock_guard
。 - 需要设置
手动解锁、超时等
,在不同作用域传递锁的所有权,应该选择std::unique_lock
- 多个线程读取同份数据,少量线程修改数据时使用
shared_lock
# 实例
#include <thread>
#include <mutex>
#include <shared_mutex>
#include <iostream>
std::mutex m1;
struct DataBuffer
{
int x;
int y;
};
DataBuffer db;
void func1()
{
m1.lock();
db.x = 100;
std::cout << "t1: " << db.x << std::endl;
m1.unlock();
}
void func2()
{
m1.lock();
db.x = 200;
std::cout << "t2: " << db.x << std::endl;
m1.unlock();
}
void func3()
{
std::lock_guard<std::mutex> lock(m1);
db.x = 100;
std::cout << "t3: " << db.x << std::endl;
}
void func4()
{
std::lock_guard<std::mutex> lock(m1);
db.x = 200;
std::cout << "t4: " << db.x << std::endl;
}
void func5()
{
std::unique_lock<std::mutex> lock(m1);
db.x = 500;
std::cout << "t50: " << db.x << std::endl;
lock.unlock();
std::this_thread::sleep_for(std::chrono::milliseconds(500));
lock.lock();
db.x = 1000;
std::cout << "t5: " << db.x << std::endl;
}
void func6()
{
std::unique_lock<std::mutex> lock(m1);
db.x = 600;
std::cout << "t60: " << db.x << std::endl;
lock.unlock();
lock.lock();
db.x = 1200;
std::cout << "t6: " << db.x << std::endl;
}
class Counter {
public:
Counter():value_(0) {}
void increment() {
std::unique_lock<std::shared_mutex> lock(m_mutex);
++value_;
}
int getValue() const {
std::unique_lock<std::shared_mutex> lock(m_mutex);
return value_;
}
private:
mutable std::shared_mutex m_mutex;
int value_;
};
int main(int argc, char* argv[])
{
std::thread t1(func1);
std::thread t2(func2);
std::thread t3(func3);
std::thread t4(func4);
std::thread t5(func5);
std::thread t6(func6);
Counter counter;
auto f7 = [&counter]() {
std::cout << "Reader 1: Value = " << counter.getValue() << std::endl;
};
std::thread reader1(f7);
auto f8 = [&counter]() {
std::cout << "Reader 2: Value = " << counter.getValue() << std::endl;
};
std::thread reader2(f8);
auto f9 = [&counter]() {
counter.increment();
};
std::thread writer(f9);
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
t6.join();
reader1.join();
reader2.join();
writer.join();
return 0;
}
# reference
1.https://en.cppreference.com/w/cpp/thread/lock_guard (opens new window)