v81.01 鸿蒙内核源码分析(读写锁) | 内核如何实现多读单写 原创 精华
鸿蒙内核源码分析
发布于 2022-2-23 09:50
浏览
2收藏
百篇博客分析|本篇为:(读写锁) | 内核如何实现多读单写
进程通讯相关篇为:
- v26.08 鸿蒙内核源码分析(自旋锁) | 当立贞节牌坊的好同志
- v27.05 鸿蒙内核源码分析(互斥锁) | 同样是锁它却更丰满
- v28.04 鸿蒙内核源码分析(进程通讯) | 九种进程间通讯方式速揽
- v29.05 鸿蒙内核源码分析(信号量) | 谁在解决任务间的同步
- v30.07 鸿蒙内核源码分析(事件控制) | 多对多任务如何同步
- v33.03 鸿蒙内核源码分析(消息队列) | 进程间如何异步传递大数据
- v76.01 鸿蒙内核源码分析(共享内存) | 进程间最快通讯方式
- v77.02 鸿蒙内核源码分析(消息封装) | 剖析LiteIpc(上)进程通讯内容
- v78.01 鸿蒙内核源码分析(消息映射) | 剖析LiteIpc(下)进程通讯机制
- v79.02 鸿蒙内核源码分析(快锁使用) | 用户态下的快锁Futex(上)
- v80.02 鸿蒙内核源码分析(快锁实现) | 内核态下的快锁Futex(下)
- v81.01 鸿蒙内核源码分析(读写锁) | 内核如何实现多读单写
特点&场景
读写锁 :是计算机程序的并发控制的一种同步机制,也称“共享-互斥锁”、多读者-单写者锁。读操作可并发重入,写操作是互斥的。
鸿蒙实现的读写锁有几个特点:
- 一把锁分成 读/写 两种操作方式,读操作和写操作本身是互斥的,待操作任务按优先级存在两个独立的链表中,是读模式还是写模式,全凭任务的优先级而定,谁高就切到哪种模式。
- 一旦切到读模式,待读链表中优先级高于待写链表中最高优先级的任务们可以同时进行读操作,这些任务并行完成后便切到写模式。
- 一旦切到写模式,待写链表中优先级高于待读链表中最高优先级的任务们不可以同时进行写操作,只能一个个执行,这些任务串行完成后便切到读模式。
- 模式可以被高优先级任务打断,例如写模式时有高优先级的待读任务到来时,将切到读模式,反之亦然。
在实际很多业务场景中读写操作的频率是不同的,读往往高几个数量级,因读操作并不改变业务数据结构,所以读锁也称为共享锁。写操作会改变数据结构,数据之间须同步,修改注定是排他的,所以也称为排它锁/互斥锁,读写锁很好的解决了这种读写不对称的业务场景。
本篇详细解剖鸿蒙是如何实现读写锁的,代码部分均有注释,尤其释放锁部分的实现很精彩,让人有种酣畅淋漓的感觉。
鸿蒙实现
OsRwlock
系列篇多次说过,内核相对独立的功能 ,都有一个核心结构体 ,是一把吃透该功能的钥匙, 读写锁便是 LosRwlock
。
解读
- 魔法数字不会陌生,很多内核模块中都会使用到 ,比如栈顶就会有 ,以此判断栈是否溢出 (值被修改表示溢出)
rwCount
记录读或者写时的任务数量,读写锁分五种操作模式:writeOwner
持有写权限的任务 ,写操作是互斥操作 ,这里记录下最后执行写操作的任务readList
所有等待读操作的任务都会挂到这里 ,并按优先级排好序writeList
所有等待写操作的任务都会挂到这里 ,并按优先级排好序
初始化读写锁
优先级 | 找位置
不论读/写,都得按优先级排序,所以当一个申请任务到来时,通过OsSchedLockPendFindPos
找到合适的位置将挂入链表的操作就很重要了
申请读锁 | OsRwlockRdPendOp
申请读模式下的锁,分三种情况:
-
- 若无人持有锁,读任务可获得锁。
-
- 若有人持有锁,读任务可获得锁,读取顺序按照任务优先级。
-
- 若有人(非自己)持有写模式下的锁,则当前任务无法获得锁,直到写模式下的锁释放。
申请写锁 | OsRwlockWrPendOp
申请写模式下的锁,分两种情况:
- 若该锁当前没有任务持有,或者持有该读模式下的锁的任务和申请该锁的任务为同一个任务,则申请成功,可立即获得写模式下的锁。
- 若该锁当前已经存在读模式下的锁,且读取任务优先级较高,则当前任务挂起,直到读模式下的锁释放。
释放读写锁 | OsRwlockPostOp
通常释放操作很简单 ,不会特书大书 ,但读写锁不一样,释放操作反而是精彩部分,因为释放就意味着等这把锁的任务有机会运行了,这些任务需要被唤醒 ,而读模式下能同时进行读操作,意味着内核要连续的唤醒等待读操作的任务 。所以出现了以下代码,站长认为这部分代码写的很精彩,必须要点赞 @note_good
解读
- 因写模式为互斥操作,背后的含义就是只能唤醒一个任务运行,所以取出首个(最高优先级)任务后,将任务唤醒加入就绪队列
OsSchedTaskWake
,申请调度 。 - 而读模式为共享模式,读任务可以同时执行,这里的同时指的是并行,在多个
CPU
上同时执行读操作。能同时执行多少个取决于写链表上的优先级,所以会先拿到最高写任务优先级pendedWriteTaskPri
用于连续唤醒读任务的优先级比较。 通过循环连续的将读任务加入就绪队列,这才是真正做到能同时进行读操作(共享锁)的代码 !!! 这段代码一定要点赞,建议反复理解,有种醍醐灌顶 ,豁然开朗的奇妙感觉。
百文说内核 | 抓住主脉络
- 百文相当于摸出内核的肌肉和器官系统,让人开始丰满有立体感,因是直接从注释源码起步,在加注释过程中,每每有心得处就整理,慢慢形成了以下文章。内容立足源码,常以生活场景打比方尽可能多的将内核知识点置入某种场景,具有画面感,容易理解记忆。说别人能听得懂的话很重要! 百篇博客绝不是百度教条式的在说一堆诘屈聱牙的概念,那没什么意思。更希望让内核变得栩栩如生,倍感亲切。
- 与代码需不断
debug
一样,文章内容会存在不少错漏之处,请多包涵,但会反复修正,持续更新,v**.xx
代表文章序号和修改的次数,精雕细琢,言简意赅,力求打造精品内容。 - 百文在 < 鸿蒙研究站 | 开源中国 | 博客园 | 51cto | csdn | 知乎 | 掘金 > 站点发布,鸿蒙研究站 | weharmonyos 中回复 百文 可方便阅读。
按功能模块:
- 前因后果 >> 总目录 | 调度故事 | 内存主奴 | 源码注释 | 源码结构 | 静态站点 | 参考文档 |
- 基础工具 >> 双向链表 | 位图管理 | 用栈方式 | 定时器 | 原子操作 | 时间管理 |
- 加载运行 >> ELF格式 | ELF解析 | 静态链接 | 重定位 | 进程映像 |
- 进程管理 >> 进程管理 | 进程概念 | Fork | 特殊进程 | 进程回收 | 信号生产 | 信号消费 | Shell编辑 | Shell解析 |
- 编译构建 >> 编译环境 | 编译过程 | 环境脚本 | 构建工具 | gn应用 | 忍者ninja |
- 进程通讯 >> 自旋锁 | 互斥锁 | 进程通讯 | 信号量 | 事件控制 | 消息队列 | 共享内存 | 消息封装 | 消息映射 | 快锁使用 | 快锁实现 | 读写锁 |
- 内存管理 >> 内存分配 | 内存管理 | 内存汇编 | 内存映射 | 内存规则 | 物理内存 |
- 任务管理 >> 时钟任务 | 任务调度 | 任务管理 | 调度队列 | 调度机制 | 线程概念 | 并发并行 | CPU | 系统调用 | 任务切换 |
- 文件系统 >> 文件概念 | 文件系统 | 索引节点 | 挂载目录 | 根文件系统 | VFS | 文件句柄 | 管道文件 |
- 硬件架构 >> 汇编基础 | 汇编传参 | 工作模式 | 寄存器 | 异常接管 | 汇编汇总 | 中断切换 | 中断概念 | 中断管理 |
- 设备驱动 >> 字符设备 | 控制台 | 远程登录 |
百万注源码 | 处处扣细节
©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
鸿蒙内核源码分析,更新至 78....zip 12.41M 70次下载
赞
3
收藏 2
回复
3
3
2
相关推荐
赞楼主坚持不懈的精神
感谢支持 , 道阻且长 , 行则将至
大佬太棒了 在操作系统这块,满腹经纶,才高八斗。openharmony里有没有您写的代码?