引言
在多线程编程中,读写锁(Read-Write Lock)是一种常见的同步机制,用于解决多个线程同时访问共享资源的问题。
读写锁
读-写问题分析
在回答上述问题之前,我们需要理解两种不同类型的线程操作:读操作和写操作。
读操作是无副作用的操作,它只从共享资源中获取信息而不改变其状态。
写操作是有副作用的操作,它会修改共享资源的状态。
当有多个线程同时访问共享资源时,我们需要确保以下几点:
一致性:所有线程看到的数据是一致的。
原子性:复合操作被视为不可分割的整体,要么全部完成,要么全部不发生。
隔离性:线程间的操作相互独立,不会互相干扰。
持久性:一旦写操作完成,结果必须持久化,即使系统崩溃也能恢复。
读写锁是一种特殊的锁机制,它把对共享资源的访问分为读操作和写操作:
读操作(共享锁):允许多个线程同时读取资源,如果当前没有写者,读锁可以被多个读者持有。当有写者尝试获取锁时,所有新的读请求都会被阻塞,直到写者释放了锁。
写操作(排他锁):只允许一个线程写入资源,写锁是排他的,当一个线程持有写锁时,其他任何线程(无论是读者还是写者)都不能访问资源。只有当写锁被释放后,其他线程才能继续。
读写锁的规则:
读-读:允许并发
读-写:互斥
写-读:互斥
写-写:互斥
C++读写锁实现
C++17引入了std::shared_mutex,这是标准库提供的读写锁实现:
#include <shared_mutex>
#include <thread>
#include <iostream>
#include <vector>
#include <chrono>
class ThreadSafeCounter {
private:
mutable std::shared_mutex mutex_;
int value_ = 0;
public:
// 写操作 - 使用独占锁
void increment() {
std::unique_lock<std::shared_mutex> lock(mutex_);
value_++;
}
// 读操作 - 使用共享锁
int get() const {
std::shared_lock<std::shared_mutex> lock(mutex_);
return value_;
}
};
在这个例子中,std::shared_lock 用于保护读操作,而 std::unique_lock 用于保护写操作。读者可以同时访问共享数据,而写者则需要独占访问。
结论
有个线程在读,能写吗?不能。如果有线程正在读取数据,那么写操作应该被推迟,直到所有的读操作完成。这是为了确保写操作不会破坏读者看到的一致性视图。
有个线程在写,能读吗?也不能。如果一个线程正在写入数据,那么所有其他线程(包括读者和写者)都必须等待,直到写操作完成。这是为了确保写操作的原子性和隔离性。