Linux内核RCU(Read Copy Update)锁简析-前传
如果你用Linux perf tool的top命令做热点纠察时,你会发现,前10名嫌疑犯里面肯定有好几个都是锁!
在进行并行多处理时,不可 避免地会遇到锁的问题,这是不可避免的,因为这一直以来也许是保护共享数据的唯一方式,被保护的区域就是临界区。而我们知道,锁的开销是巨大的,因为它不 可避免地要么等待,要么让别人等待,然而这并不是开销的本质,开销的本质在于很多锁都采用了“原子操作”这么一个技术,如此一个原子操作会对总线或者 cache一致性造成很大的影响,比如要对一个变量进行原子加1,不要认为它很简单,其实背后会有很多不希望的操作,在某架构的处理器上,首先要LOCK 总线,这意味着LOCK不解除期间,其它处理器不能访存(起码是内存的某些区域),可能还要涉及到刷cache,或者触发cache一致性操作...这还 不算最猛的打击,在某些架构上,存在内存栅栏,它会刷掉CPU的流水线,刷掉cache,几乎所有的为优化而设计的方案全部失效,当然,这是代价,收益就 是你保护了临界区。
你要保护临界区,你要付出代价,这个代价如果用复杂的锁来支付的话,未免有点大。非要这样子吗?也许是你的数据结构设计地不好,也许是你的代码流设计地不 好,比如多个线程同时读共享数据,两个线程一个读一个写,能否采用环形缓冲区来减轻竞争呢?事实上很多诸如网卡,硬盘等共享外设驱动程序都是这么玩的,代 码只要保证读指针和写指针不相互超越即可,这样可以最小化锁的使用,当然这只是一个非常简单的例子。
设计好的数据结构和代码流程是一方面,但是这个层次不够抽象,更好的方式就是设计一种更加优化的锁。读写锁这种不对称的锁应对读者多写者少的情景是一种优 化的锁,它对读者的优待就是无需等待,只要没有写者就可以直接读,否则才等待。而对于写者,它需要等待所有读者的完成。这种读写的实现可以依赖于另一种叫 做自旋锁的机制实现,我的一个实现如下所示:
typedef struct {spinlock_t *spinlock;atomic_t readers;}rwlock_t;
static inline void rdlock(rwlock_t *lock)
{spinlock_t *lck = lock->spinlock;if (likely(!lock->readers++))spin_lock(lck);
}static inline void rdunlock(rwlock_t *lock)
{spinlock_t *lck = lock->spinlock;if (likely(!--lock->readers))spin_unlock(lck);
}static inline void wrlock(rwlock_t *lock)
{spin_lock(lock->spinlock);
}static inline void wrunlock(rwlock_t *lock)
{spin_unlock(lock->spinlock);
}
很OK,不是吗?但是最好的方案就是彻底抛弃锁,彻底不用锁。
我曾经在设计我的转发表的时候,为了降低lock开销,我为每个CPU复制了一个局部的本地转发表,这些转发表是一致的,由路由表生成,心想这就可以避免 竞争,然而,这些转发表总要面临更新问题,如何更新它们??我最初采用的方式是采用IPI(处理器间中断),在处理函数中,停掉处理线程,然后更新数据, 最后开启线程,这样可以在处理期间避免lock。十分合理,不是吗?可是我想复杂了。
仔细看看读写锁的写锁,它鲁莽地进行了标准锁定操作,而读锁也是在第一个读者进来的时候采用了锁定动作。这些锁定操作导致的等待可以避免吗?看看我原始的 IPI方案,停掉线程是为了防止读者读到错误的数据,实际上是将主动将执行流让位给了写者,写者先来,然后再看看读写锁中的写者,发现有读者存在时,没有 主动地让位,而只是被动地等待,这种等待很无聊!
能否将我的方式和读写锁的方式结合呢?
怎么结合?按照刚刚的思路,无非就是为写者是被动等待还是抢先读者做一个决策!但是它还有一个别的选择,那就是先按照自己的流程写数据,不是写原始数据, 而是写原始数据的一份拷贝(伟大的写时拷贝),然后将这件事挂在一个未竟事务链表上直接走人,等待系统发现所有的读者都完成时用链表上的数据逐个覆盖原始 数据。这是个多么好的结合,这就是伟大的RCU锁。读者的代价就是简单地标示一下有人读即可,而写者也无需等待持锁,直接写副本,写完走人,后来的事就交 给系统了....
Linux内核RCU(Read Copy Update)锁简析-前传相关推荐
- Linux内核RCU(Read Copy Update)锁简析
在非常早曾经,大概是2009年的时候.写过一篇关于Linux RCU锁的文章<RCU锁在linux内核的演变>,如今我承认.那个时候我尽管懂了RCU锁,可是我没有能力用一种非常easy的描 ...
- Linux RCU锁简析
最近遇到一个问题,大压力测试下咬狗了,定位出来跟RCU相关,还是先简单的捋一捋RCU,也好看看后面能否对RCU做些特定场景下的优化. 网上RCU相关的技术博客比较多,先列几个可供参考的: MagicB ...
- 浅谈Linux内核RCU机制原理
RCU(Read-Copy Update)是数据同步的一种方式,在当前的Linux内核中发挥着重要的作用.RCU主要针对的数据对象是链表,目的是提高遍历读取数据的效率,为了达到目的使用RCU机制读取数 ...
- linux内核rcu,linux内核rcu机制详解
RCU(Read-Copy Update)是数据同步的一种方式,在当前的Linux内核中发挥着重要的作用.RCU主要针对的数据对象是链表,目的是提高遍历读取数据的效率,为了达到目的使用RCU机制读取数 ...
- linux内核 RCU机制详解
简介 RCU(Read-Copy Update)是数据同步的一种方式,在当前的Linux内核中发挥着重要的作用.RCU主要针对的数据对象是链表,目的是提高遍历读取数据的效率,为了达到目的使用RCU机制 ...
- linux内核 RCU机制概述
简介 RCU(Read-Copy Update)是数据同步的一种方式,在当前的Linux内核中发挥着重要的作用.RCU主要针对的数据对象是链表,目的是提高遍历读取数据的效率,为了达到目的使用RCU机制 ...
- 深入linux内核架构--第五章 锁与进程间通信
内容简介:主要讲解了Linux各个独立进程间(或线程间)相互通信的机制(主要是System V机制),由于涉及到进程间资源共享,引入资源保护问题,也就是Linux的锁. 5.1 控制机制 首先通过一个 ...
- linux内核RCU
RCU背景 RCU在2002年中增加到内核中的,是一种基于互斥的同步机制,当读多写少并且读性能要求较高时候能够达到最大的效果,它总体上属于一种空间换时间的方式,用短时间内占用额外的内存来保证快速的访问 ...
- linux内核内存屏障,从硬件引申出内存屏障,带你深入了解Linux内核RCU
本文简介 本文从硬件的角度引申出内存屏障,这不是内存屏障的详尽手册,但是相关知识对于理解RCU有所帮助.这不是一篇单独的文章,这是<谢宝友:深入理解Linux RCU>系列的第2篇,前序文 ...
最新文章
- 数论 - SGU 105 DIV3
- 互联网1分钟 |1120
- 单页应用程序的Spring Boot静态Web资源处理
- 关于通过反汇编查看dll的方法【转】(
- windows linux mysql_linux/windows环境mysql数据库安装与使用
- Mac osx 下配置ANT
- Spring Cloud Gateway (七)处理流程解析
- 深度学习笔记_卷积神经网络基本概念
- 泰安的雾霾确实有点大
- 中国范围的经纬度及部分城市经纬度
- 宇视网络视频录像机添加摄像机提示离线
- 用c语言编程一个滑稽图案,滑稽,用C语言搞个鼠标连点器
- springCloud微服务生态圈囊括—— 服务注册,服务调用,服务降级,熔断。(1)
- Global land use changes are four times greater than previously estimated
- RUNA WFE,workflow environment based on JBoss' JBPM engine
- Android Studio连接驱动装不上应用程序无法正常启动(oxc000007b)
- Spring Boot 项目鉴权的 4 种方式
- 我的2019年计划清单
- 第一周-PDCA学习模型
- Office2016卡顿的原因及解决方法
热门文章
- 掘金后端 mysql优化_vue服务端渲染项目(ssr)仿掘金、后台页面是react spa、服务层nodejs、koa、mysql编写的一套多权限内容管理系统...
- 这些面试用例设计,你肯定遇到过(朋友圈、电梯、发红包、支付)
- 程序员:进不了大厂,就“永无出头之日”了?
- 360怎么看电脑配置_怎么样查看电脑配置?5种方法查看电脑硬件配置好坏图文详解...
- java数组变量_关于java 的数组引用变量
- java 任务栏程序_如何在任务栏显示java程序图标
- papers to read
- 26留数及其应用(二)
- DenseNet细节
- Fashion Mnist中的softmax应用