C++读写锁的核心设计思路
读写锁的核心目标是区分读操作和写操作的访问权限,读操作之间可以共享资源,读操作和写操作、写操作和写操作之间需要互斥。实现时需要维护几个关键状态:当前活跃的读线程数量、是否有写线程正在等待或持有锁、等待队列的处理逻辑。我们可以借助C++标准库的std::mutex保护内部状态,用std::condition_variable实现线程的等待和唤醒。

核心状态定义
首先需要定义读写锁的内部状态变量,包括读计数、写标志、等待写计数,同时搭配互斥量和条件变量:
#include <mutex>
#include <condition_variable>
#include <atomic>
class ReadWriteLock {
private:
std::mutex mtx; // 保护内部状态的互斥量
std::condition_variable read_cv; // 读线程等待的条件变量
std::condition_variable write_cv;// 写线程等待的条件变量
int read_count = 0; // 当前持有读锁的线程数
int write_count = 0; // 等待或持有写锁的线程数
bool is_writing = false; // 是否有线程正在写
};
读锁的获取与释放
读锁的获取逻辑需要满足:如果没有写线程正在操作或等待,就可以增加读计数并获取锁;如果有写线程等待,读线程需要进入等待队列,避免写线程饥饿。
public:
// 获取读锁
void lock_read() {
std::unique_lock<std::mutex> lock(mtx);
// 等待条件:没有写线程正在操作,且没有写线程在等待
read_cv.wait(lock, [this]() {
return !is_writing && write_count == 0;
});
read_count++;
}
// 释放读锁
void unlock_read() {
std::unique_lock<std::mutex> lock(mtx);
read_count--;
// 如果读计数归零,且存在等待的写线程,唤醒一个写线程
if (read_count == 0 && write_count > 0) {
write_cv.notify_one();
}
}
写锁的获取与释放
写锁的获取逻辑需要满足:如果没有任何读线程持有锁,且没有写线程正在操作,就可以获取写锁;否则进入等待队列,等待所有读线程释放锁且写线程释放锁。
// 获取写锁
void lock_write() {
std::unique_lock<std::mutex> lock(mtx);
write_count++;
// 等待条件:没有读线程持有锁,且没有写线程正在操作
write_cv.wait(lock, [this]() {
return read_count == 0 && !is_writing;
});
is_writing = true;
write_count--;
}
// 释放写锁
void unlock_write() {
std::unique_lock<std::mutex> lock(mtx);
is_writing = false;
// 优先唤醒等待的写线程,如果没有写线程等待再唤醒所有读线程
if (write_count > 0) {
write_cv.notify_one();
} else {
read_cv.notify_all();
}
}
};
读写锁的使用示例
下面通过一个简单的共享数据访问示例,展示我们实现的读写锁的使用方式:
#include <iostream>
#include <thread>
#include <vector>
int shared_data = 0;
ReadWriteLock rw_lock;
// 读线程函数
void read_task(int thread_id) {
rw_lock.lock_read();
std::cout << "线程" << thread_id << "读取共享数据:" << shared_data << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
rw_lock.unlock_read();
}
// 写线程函数
void write_task(int thread_id, int value) {
rw_lock.lock_write();
shared_data = value;
std::cout << "线程" << thread_id << "写入共享数据:" << shared_data << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(200));
rw_lock.unlock_write();
}
int main() {
std::vector<std::thread> threads;
// 创建3个写线程
for (int i = 0; i < 3; i++) {
threads.emplace_back(write_task, i, i + 10);
}
// 创建5个读线程
for (int i = 0; i < 5; i++) {
threads.emplace_back(read_task, i + 3);
}
// 等待所有线程结束
for (auto& t : threads) {
t.join();
}
return 0;
}
实现注意事项
- 写线程优先策略:上述实现中写线程等待时,读线程不会继续获取锁,避免写线程长时间等待,适合写操作需要及时执行的场景。
- 条件变量的虚假唤醒:使用
std::condition_variable::wait时必须传入谓词,避免虚假唤醒导致状态错误。 - 锁的配对使用:获取读锁必须对应释放读锁,获取写锁必须对应释放写锁,否则会导致状态异常或死锁。
- C++17及以上标准已经提供了
std::shared_mutex,实际开发中如果不是需要自定义读写锁逻辑,优先使用标准库提供的实现,可靠性和性能更有保障。
C++读写锁C++并发编程读写锁实现std_thread修改时间:2026-06-26 12:54:30