-
Notifications
You must be signed in to change notification settings - Fork 385
ipc::rw_lock
mutouyun edited this page Dec 9, 2025
·
2 revisions
读写锁(Reader-Writer Lock),支持多个读者并发访问,写者独占访问。基于自旋锁实现。
namespace ipc {
class rw_lock {
public:
rw_lock() = default;
// 禁止拷贝和移动
rw_lock(const rw_lock&) = delete;
rw_lock& operator=(const rw_lock&) = delete;
rw_lock(rw_lock&&) = delete;
rw_lock& operator=(rw_lock&&) = delete;
void lock() noexcept; // 写锁(独占)
void unlock() noexcept; // 释放写锁
void lock_shared() noexcept; // 读锁(共享)
void unlock_shared() noexcept; // 释放读锁
};
} // namespace ipcipc::rw_lock是一个基于原子操作的读写锁实现,允许:
- 多个读者同时持有读锁(共享访问)
- 单个写者独占写锁(排他访问)
- 写者优先:有写者等待时,新的读者会阻塞
特点:
- ✅ 多读者并发,提升读密集场景性能
- ✅ 写者独占,保证数据一致性
- ✅ 无系统调用,基于原子操作
⚠️ 仅适用于进程内同步⚠️ 写者会阻塞所有读者
| 成员函数 | 说明 |
|---|---|
lock |
获取写锁(独占) |
unlock |
释放写锁 |
lock_shared |
获取读锁(共享) |
unlock_shared |
释放读锁 |
void lock() noexcept;获取写锁(独占访问)。会阻塞直到:
- 没有其他写者持有锁
- 所有读者都释放了锁
返回值:无
异常:不抛出异常(noexcept)
void unlock() noexcept;释放写锁。
返回值:无
异常:不抛出异常(noexcept)
void lock_shared() noexcept;获取读锁(共享访问)。会阻塞直到:
- 没有写者持有锁
- 允许多个读者同时持有读锁
返回值:无
异常:不抛出异常(noexcept)
void unlock_shared() noexcept;释放读锁。
返回值:无
异常:不抛出异常(noexcept)
#include "libipc/rw_lock.h"
#include <thread>
#include <vector>
ipc::rw_lock lock;
int shared_data = 0;
// 写者
void writer() {
lock.lock();
shared_data++;
std::cout << "Writer updated data to " << shared_data << std::endl;
lock.unlock();
}
// 读者
void reader(int id) {
lock.lock_shared();
std::cout << "Reader " << id << " read data: " << shared_data << std::endl;
lock.unlock_shared();
}
int main() {
std::vector<std::thread> threads;
// 启动多个读者(可以并发)
for (int i = 0; i < 5; ++i) {
threads.emplace_back(reader, i);
}
// 启动写者
threads.emplace_back(writer);
for (auto& t : threads) {
t.join();
}
return 0;
}// 写锁守卫
class write_lock_guard {
ipc::rw_lock& lock_;
public:
explicit write_lock_guard(ipc::rw_lock& lock) : lock_(lock) {
lock_.lock();
}
~write_lock_guard() {
lock_.unlock();
}
write_lock_guard(const write_lock_guard&) = delete;
write_lock_guard& operator=(const write_lock_guard&) = delete;
};
// 读锁守卫
class read_lock_guard {
ipc::rw_lock& lock_;
public:
explicit read_lock_guard(ipc::rw_lock& lock) : lock_(lock) {
lock_.lock_shared();
}
~read_lock_guard() {
lock_.unlock_shared();
}
read_lock_guard(const read_lock_guard&) = delete;
read_lock_guard& operator=(const read_lock_guard&) = delete;
};
// 使用RAII守卫
void safe_write() {
write_lock_guard guard(lock);
shared_data++; // 自动加锁和解锁
}
void safe_read() {
read_lock_guard guard(lock);
int value = shared_data; // 自动加锁和解锁
}// 缓存系统示例
class Cache {
ipc::rw_lock lock_;
std::map<std::string, std::string> data_;
public:
// 读操作(高频,使用共享锁)
std::string get(const std::string& key) {
lock_.lock_shared();
auto it = data_.find(key);
std::string result = (it != data_.end()) ? it->second : "";
lock_.unlock_shared();
return result;
}
// 写操作(低频,使用独占锁)
void set(const std::string& key, const std::string& value) {
lock_.lock();
data_[key] = value;
lock_.unlock();
}
};✅ 适合使用rw_lock的场景:
- 读操作频繁,写操作较少
- 读操作耗时较短
- 需要多个读者并发访问
- 读者之间无需互斥
❌ 不适合使用rw_lock的场景:
- 写操作频繁(应使用spin_lock或mutex)
- 读操作很少(额外开销不值得)
- 需要进程间同步(应使用ipc::sync::mutex)
- 读操作耗时很长(可能饥饿写者)
在读多写少场景下的性能(10读者:1写者):
| 锁类型 | 吞吐量 |
|---|---|
| rw_lock | 高 (读者并发) |
| spin_lock | 中 (完全互斥) |
| mutex | 中 (完全互斥) |
class rw_lock {
using lc_ui_t = std::uint32_t;
std::atomic<lc_ui_t> lc_ { 0 };
enum : lc_ui_t {
w_mask = 0x7FFF'FFFF, // 读者计数掩码
w_flag = 0x8000'0000 // 写者标志位
};
public:
void lock() noexcept {
// 1. 设置写者标志
// 2. 等待所有读者退出
}
void lock_shared() noexcept {
// 1. 等待写者标志清除
// 2. 增加读者计数
}
};关键点:
- 使用32位原子整数:最高位是写者标志,低31位是读者计数
- 写者设置标志位后等待读者计数降为0
- 读者检查写者标志,无写者时增加计数
- 使用CAS (Compare-And-Swap) 保证原子性
- 写者优先:有写者等待时,新的读者会被阻塞
- 不可递归:同一线程不能递归加锁
- 不可升级:不能将读锁升级为写锁(会死锁)
- 不可降级:不能将写锁降级为读锁(不支持)
- 饥饿可能:写者过多可能导致读者饥饿
- 进程内使用:仅用于同一进程内的线程同步
- 避免长时间持锁:读者持锁时间过长会阻塞写者
-
ipc::spin_lock- 自旋锁 -
ipc::sync::mutex- 进程间互斥锁 - rw_lock.h - 头文件文档