读写锁是一种同步机制,用于控制多个线程对共享资源的访问,其核心特性:
适用场景:读多写少的场景(如数据库缓存、日志系统),相比普通互斥锁(Mutex)能显著提升并发性。
维度 | 互斥锁(Mutex) | 读写锁(Reader-Writer Lock) |
---|---|---|
读操作并发 | 同一时间仅1线程访问 | 允许多线程同时读 |
写操作开销 | 低(简单加锁) | 高(需协调读/写线程) |
典型场景 | 读写均衡或写多读少 | 读多写少(如配置中心、缓存) |
适用范围:Linux/macOS等UNIX-like系统,C++11之前的主流方案。
#include
// 初始化读写锁
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
// 加读锁(阻塞式)
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
// 尝试加读锁(非阻塞,成功返回0,失败返回EBUSY)
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
// 加写锁(阻塞式)
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
// 尝试加写锁(非阻塞)
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
// 解锁
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
// 销毁锁
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
#include
#include
#include
#include
pthread_rwlock_t rwlock;
std::vector<int> cache;
// 读线程:获取读锁,读取缓存
void read_cache(int id) {
pthread_rwlock_rdlock(&rwlock);
std::cout << "Thread " << id << " reading: ";
for (auto val : cache) {
std::cout << val << " ";
}
std::cout << std::endl;
pthread_rwlock_unlock(&rwlock);
}
// 写线程:获取写锁,更新缓存
void update_cache(int id, std::vector<int> new_data) {
pthread_rwlock_wrlock(&rwlock);
cache = new_data;
std::cout << "Thread " << id << " updated cache." << std::endl;
pthread_rwlock_unlock(&rwlock);
}
int main() {
pthread_rwlock_init(&rwlock, nullptr);
cache = {1, 2, 3};
// 启动3个读线程
std::thread readers[3];
for (int i = 0; i < 3; ++i) {
readers[i] = std::thread(read_cache, i);
}
// 启动1个写线程(会等待读线程释放锁)
std::thread writer(update_cache, 4, {4, 5, 6});
// 等待所有线程结束
for (auto& th : readers) th.join();
writer.join();
pthread_rwlock_destroy(&rwlock);
return 0;
}
pthread_rwlock_init
和pthread_rwlock_destroy
,避免内存泄漏。适用范围:C++20及以上标准,跨平台(Windows/Linux/macOS)。
std::shared_mutex
:底层实现读写锁语义。std::shared_lock
:用于获取读锁(共享锁)。std::unique_lock
:用于获取写锁(排他锁)。#include
#include
#include
#include
std::shared_mutex rw_mutex;
int counter = 0;
// 读操作:统计计数器值
void read_counter(int id) {
std::shared_lock<std::shared_mutex> lock(rw_mutex); // 自动获取读锁
std::cout << "Thread " << id << ": Counter = " << counter << std::endl;
}
// 写操作:增加计数器值
void increment_counter(int id, int times) {
std::unique_lock<std::shared_mutex> lock(rw_mutex); // 自动获取写锁
for (int i = 0; i < times; ++i) {
counter++;
}
std::cout << "Thread " << id << " updated counter to " << counter << std::endl;
}
int main() {
std::vector<std::thread> threads;
// 启动5个读线程
for (int i = 0; i < 5; ++i) {
threads.emplace_back(read_counter, i);
}
// 启动2个写线程
for (int i = 5; i < 7; ++i) {
threads.emplace_back(increment_counter, i, 100);
}
for (auto& th : threads) th.join();
return 0;
}
std::shared_lock
和std::unique_lock
自动管理锁的生命周期,避免忘记解锁。适用场景:需要理解底层原理,或在不支持C++20的环境中模拟读写锁。
#include
#include
class ReadWriteLock {
private:
std::mutex mtx;
std::condition_variable read_cv, write_cv;
int reader_count = 0;
bool writer_active = false;
public:
// 获取读锁
void lock_read() {
std::unique_lock<std::mutex> lock(mtx);
// 等待写锁释放
read_cv.wait(lock, [this]() { return !writer_active; });
reader_count++;
}
// 释放读锁
void unlock_read() {
std::unique_lock<std::mutex> lock(mtx);
reader_count--;
if (reader_count == 0) {
write_cv.notify_one(); // 唤醒等待的写线程
}
}
// 获取写锁
void lock_write() {
std::unique_lock<std::mutex> lock(mtx);
// 等待所有读线程释放且无写锁
write_cv.wait(lock, [this]() { return reader_count == 0 && !writer_active; });
writer_active = true;
}
// 释放写锁
void unlock_write() {
std::unique_lock<std::mutex> lock(mtx);
writer_active = false;
read_cv.notify_all(); // 唤醒所有读线程
write_cv.notify_one(); // 唤醒可能等待的写线程
}
};
reader_count
计数)。reader_count==0
)且无其他写锁。操作类型 | POSIX读写锁 | std::shared_mutex | 自定义读写锁(读优先) |
---|---|---|---|
读锁加锁耗时 | 低 | 中 | 高 |
写锁加锁耗时 | 中 | 中 | 高 |
适用场景 | 系统级开发 | 现代C++应用 | 学习/定制化需求 |
std::shared_mutex
和std::shared_lock
提供简洁、安全的读写锁实现,推荐用于新项目。lock_guard
或unique_lock
,避免锁的作用域泄漏。读写锁是多线程编程中提升读性能的关键工具,其核心在于分离读/写操作的并发策略:
合理使用读写锁能显著优化读多写少场景的并发性,但需注意避免死锁和饥饿问题,结合具体业务场景选择最优方案。
参考资料: