RCU机制学习

RCU机制学习RCU 是一组 Linux 内核 API 实现了一种同步机制 允许多个读者与写者并发操作而不需要任何锁 这种同步机制可以用于保护通过指针访问的数据 RCU 读者只需要很低的额外成本 在典型的服务器内核配置下甚至是 0 成本 如果可能有多个写者 写者之间需要其他同步机制 除了使用 RCUAPI 直接访问指针数据 更多的使用方式是封装 API 使其用于链表访问 RCU 适用于读取数据量大而且可以接收读取到旧数据的场景

读者0额外成本是怎么做到的?

在典型的服务器内核配置(非抢占内核配置并使用gcc编译)时进入临界函数,内存屏障并不会生成任何汇编代码,只是通知编译器对临界区内外代码不要做乱序并且进入临界区后会刷新寄存器(防止CPU乱序的内存屏障操作在其他API中添加),离开临界区的代码同样最后只有一个内存屏障,因此可以看做是0额外成本。

static inline void rcu_read_lock(void) { 
    __rcu_read_lock(); __acquire(RCU); rcu_lock_acquire(&rcu_lock_map); rcu_lockdep_assert(rcu_is_watching(), "rcu_read_lock() used illegally while idle"); } static inline void __rcu_read_lock(void) { 
    preempt_disable(); } #define preempt_disable() barrier() #define barrier() __asm__ __volatile__("": : :"memory") 

在RCU机制下写数据成本如何?

需要等到此前读者完成,需要等待,可以通过注册异步执行的函数的形式处理。

<include/linux/rcupdate.h> static inline void rcu_read_lock(void) { 
    __rcu_read_lock(); __acquire(RCU); rcu_read_acquire(); } 

该函数实现里面有三个函数调用,但是实质性的工作由第一个函数__rcu_read_lock()来完成,__rcu_read_lock通过调用,preempt_disable关闭内核可抢占性,但是中断是允许的,假设读取者正处于rcu临界区中且刚读取了一个共享数据区的指针p(但是还没有访问p的数据成员),发生了一个中断,而该中断例程ISR恰好需要修改p所指向的数据区,按照RCU的设计原则,ISR会新分配一个同样大小的数据区new_p,再把老数据区的数据拷贝过来,接着在new_p的基础上做修改,不存在对p的并发访问,因此RCU是一种免锁机制。ISR在把数据更新的工作做完之后,将new_p的值重新赋给p,最后注册一个回调函数用以在适当的时候释放老指针。因此老指针p上的所有引用就结束了,释放p不会有问题。当中断处理例程做完这些工作之后,返回,被中断的例程将依然访问到p空间上的数据,也就是老数据,这样的结果是RCU允许的。RCU规则造成的资源短暂性不一致问题是允许的。

只需要通过rcu_read_lock关闭内核可抢占性就行,因为他使得当前读者进程即使在临界区发生了中断,也不会切换到其他进程。如果在rcu的临界区中调用了一个函数,该函数可能睡眠,那么RCU的设计规则就遭到了破坏,系统将进入一种不稳定的状态。

syschronize_rcu的实现则利用了等待队列,在它的实现过程中也会像call_rcu那样像之前处理器链表中加入节点,其回调函数是rcu_process_callbacks会检查当前处理器是否经历了一个休眠期,直到系统中的所有处理器都发生一次进程切换,因而wakeme_after_rcu被rcu_process_callbacks所调用以唤醒睡眠syschronize_rcu,被唤醒后,可以释放老指针了。

所以我们看到,call_rcu返回后其注册的回调函数可能还没被调用,因而也就意味着老指针还未被释放,而synchronize_rcu返回后老指针肯定被释放了。所以,是调用call_rcu还是synchronize_rcu,要视特定需求与当前上下文而定,比如中断处理的上下文肯定不能使用 synchronize_rcu函数了。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/225157.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月17日 上午9:58
下一篇 2026年3月17日 上午9:59


相关推荐

  • Gemini 3与Nano Banana实战!第一本书重磅上市!

    Gemini 3与Nano Banana实战!第一本书重磅上市!

    2026年3月13日
    2
  • Android布局详解

    Android布局详解Android六大基本布局分别是:线性布局LinearLayout、相对布局RelativeLayout、帧布局FrameLayout、表格布局TableLayout、网格布局GridLayout。其中,表格布局是线性布局的子类。网格布局是android4.0后新增的布局。普通视图还是布局都继承自View,其中ViewGroup就是所有布局的父类,ViewGroup继承自View…

    2022年6月2日
    39
  • java递归查询数据库数据[通俗易懂]

    java递归查询数据库数据[通俗易懂]先查询第一层的数据,然后调用递归循环第一层的数据,查询父Id等于第一层的Id,执行完成后第一层一下的所有数据就全部查询出来了。。。publicList&lt;Information&gt;getTreeList(IntegertopId){ Stringhql="fromInformationwhereisDelete=2andid="+topId; List&l…

    2025年11月23日
    4
  • 安装matplotlib模块「建议收藏」

    安装matplotlib模块「建议收藏」matplotlib是python中强大的画图模块。首先确保已经安装python,然后用pip来安装matplotlib模块。进入到cmd窗口下,执行python-mpipinstall-Upipsetuptools进行升级。接着键入python-mpipinstallmatplotlib进行自动的安装,系统会自动下载安装包。安装完成后,可以用python-mpip…

    2022年6月21日
    52
  • Q学习(Q learning) 强化学习的简单例子 Matlab实现 可视化「建议收藏」

    Q学习(Q learning) 强化学习的简单例子 Matlab实现 可视化「建议收藏」参考链接:https://blog.csdn.net/Maggie_zhangxin/article/details/73481417实现的内容很简单,存为.m文件可以直接在matlab上运行,就是利用Q学习(Qlearning)完成自主路径寻优简单示例,并进行可视化,Q学习部分参考了如上链接中的内容,供大家交流学习使用,请多提宝贵意见如图为最终路径,红色方框代表机器人,绿色区域代表障碍…

    2022年10月3日
    4
  • 群 环 域_群环域属于什么学科

    群 环 域_群环域属于什么学科群(Group)两个元素二元运算得到一个新元素环(Ring)上tian’jia在阿贝尔群(交换群)

    2025年5月23日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号