锁
锁
1. 锁的分类
1.1 自旋锁
自旋锁是一种忙等待锁,当线程获取锁失败时,会一直循环等待,直到获取到锁为止。
自旋锁的优点是避免了线程切换的开销,缺点是如果锁竞争激烈,会导致CPU资源浪费。
1.2 互斥锁
互斥锁是一种阻塞锁,当线程获取锁失败时,会阻塞当前线程,直到获取到锁为止。
互斥锁的优点是可以保证线程安全,缺点是可能会导致线程阻塞,影响程序性能。
手撕读写锁
1. 读写锁的原理
读写锁,又称为共享-独占锁,是计算机程序的并发控制的一种同步机制,它允许多个线程同时读取共享数据,但是只允许一个线程写入共享数据,在写入共享数据时,会独占锁,其他线程不能读取也不能写入。
读写锁主要包含以下几个要点:
- 读锁:允许多个线程同时获取读锁,但是不能获取写锁。
- 写锁:只能有一个线程获取写锁,其他线程不能获取读锁和写锁。
- 写锁优先级:当一个线程获取了写锁,其他线程不能获取读锁和写锁,直到写锁被释放。(推荐)
- 读锁优先级:当一个线程获取了读锁,其他线程可以继续获取读锁,但是不能获取写锁,直到所有读锁被释放,需注意写饥饿问题。
- 公平优先:读写锁是否公平,即获取锁的顺序是否按照请求的顺序。
读写锁的实现需要考虑以下几个问题:
- 如何实现读锁和写锁的互斥?
 两个条件变量,一个用于读锁,一个用于写锁。
- 如何实现读锁和写锁的优先级?
- 如何实现读锁和写锁的同步?
 使用三个变量,一个记录活跃读者的数量,一个记录等待写者的数量,一个标记是否有活跃写者,只用等待写者数量无法准确判断是否有读者在写入。
2. 读写锁的实现
2.1 读写锁的接口设计
class Lock{
private:
    std::mutex mtx_;
public:
    Lock(){};
    ~Lock(){};
    void lock(){ mtx_.lock(); }
    void unlock(){ mtx_.unlock(); }
    std::mutex& getMutex(){ return &mtx_; }
};
class RWLock {
public:
    RWLock();
    ~RWLock();
    void readLock();
    void readUnlock();
    void writeLock();
    void writeUnlock();
private:
    // 读写锁的成员变量
    Lock base_lock_;
    std::condition_variable read_cv_;
    std::condition_variable write_cv_;
    int active_readers_ = 0; // 活跃读者数量
    int waiting_writers_ = 0; // 等待写者数量
    bool active_writer_ = false; // 是否有活跃写者
};
2.2 读写锁的实现
RWLock::RWLock() {
    active_readers_ = 0;
    waiting_writers_ = 0;
    active_writer_ = false;
}
RWLock::~RWLock() {
    active_readers_ = 0;
    waiting_writers_ = 0;
    active_writer_ = false;
}
void RWLock::readLock() {
    std::unique_lock<std::mutex> lock(base_lock_.getMutex());
    // 如果没有活跃写者,并且没有等待的写者,则获取读锁
    read_cv_.wait(lock, [this]() {
        return !active_writer_ && waiting_writers_ == 0;
    });
    active_readers_++;
}
void RWLock::readUnlock() {
    std::unique_lock<std::mutex> lock(base_lock_.getMutex());
    active_readers_--;
    // 如果没有活跃读者,并且有等待的写者,则通知写者
    if (active_readers_ == 0 && waiting_writers_ > 0) {
        write_cv_.notify_one();
    }
}
void RWLock::writeLock() {
    std::unique_lock<std::mutex> lock(base_lock_.getMutex());
    // 如果没有活跃读者,并且没有活跃写者,则获取写锁
    waiting_writers_++;
    write_cv_.wait(lock, [this]() {
        return !active_writer_ && active_readers_ == 0;
    });
    waiting_writers_--;
    active_writer_ = true;
}
void RWLock::writeUnlock() {
    std::unique_lock<std::mutex> lock(base_lock_.getMutex());
    active_writer_ = false;
    // 如果有等待的写者,则通知写者
    if (waiting_writers_ > 0) {
        write_cv_.notify_one();
    }
    // 如果有等待的读者,则通知读者
    else if (active_readers_ > 0) {
        read_cv_.notify_all();
    }
}
//RAII 写法
class ReadLock {
public:
    ReadLock(RWLock& rwlock) : rwlock_(rwlock) {
        rwlock_.readLock();
    }
    ~ReadLock() {
        rwlock_.readUnlock();
    }
    // 禁用拷贝构造函数和赋值运算符
    ReadLock(const ReadLock&) = delete;
    ReadLock& operator=(const ReadLock&) = delete;
private:
    RWLock& rwlock_;
};
class WriteLock {
public:
    WriteLock(RWLock& rwlock) : rwlock_(rwlock) {
        rwlock_.writeLock();
    }
    ~WriteLock() {
        rwlock_.writeUnlock();
    }
    // 禁用拷贝构造函数和赋值运算符
    WriteLock(const WriteLock&) = delete;
    WriteLock& operator=(const WriteLock&) = delete;
private:
    RWLock& rwlock_;
};
 
                     
                    
                 
                    
                 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号