当前位置: 首页 > news >正文

目录
    • 1. 锁的分类
      • 1.1 自旋锁
      • 1.2 互斥锁
    • 手撕读写锁
      • 1. 读写锁的原理
      • 2. 读写锁的实现
        • 2.1 读写锁的接口设计
        • 2.2 读写锁的实现

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_;
};
http://www.hskmm.com/?act=detail&tid=24915

相关文章:

  • 1 洛谷题解修正器
  • 防止语言模型性能倒退的新方法
  • Delphi 解决IniFiles中文乱码
  • Tarjan详解
  • RAG入门 - Retriever(1) - 指南
  • 分布式微服务系统架构第142集:全栈构建
  • 2025 年电永磁吊具制造厂家 TOP 企业品牌推荐排行榜全新发布,含大型电永磁吊具,全覆盖,起重,小型,钢板,钢板电永磁吊具公司推荐!
  • QBXT2025S刷题 Day4题
  • 实用指南:云原生时代 Kafka 深度实践:03进阶特性与最佳实践
  • 【VM虚拟机】VM新版本,虚拟机中键盘输入延迟卡顿
  • 2025石灰源头厂家最新推荐榜单:深度解析生石灰,熟石灰物流效率与综合实力
  • AtCoder Beginner Contest 426 游记
  • 如何把MCP服务集成到智能体?手把手教学(含视频教程)
  • bootimg.exe检查验证备份导出的img镜像文件是否正常
  • 华为云Flexus+DeepSeek征文|华为云Flexus服务器dify高效的平台通过自然语言转sql并执行搭建电商数据分析
  • 《独立开发者精选工具》第 019 期
  • 活着,就像明天就要死去一样
  • vue漏洞
  • 网站第一开在浏览器中打开慢的原因
  • [JVM] JVM内存调优 - 教程
  • 全面解析DoS攻击防护与应对策略
  • day16 课程(面向对象三大特性:继承 多态 属性)
  • C++ Vector算法精讲与底层探秘:从经典例题到性能优化全解析 - 指南
  • 大数据分析基础及应用案例:第二周学习报告 —— 初探 NumPy 与 Pandas
  • 强化学习人类反馈训练新方法解析
  • 在MyBatis中collection属性的命名规则主要取决于传入参数的类型
  • 20250919_QQ_ICMP
  • 2025CSP-S模拟赛59 比赛总结
  • MCP协议重构AI Agent生态:万能插槽如何终结器具孤岛?
  • 文件的物理结构II