Linux内核Radix Tree(二)
1. 并发技术
由于需要页高速缓存是全局的,各进程不停的访问,必须要考虑其并发性能,单纯的对一棵树使用锁导致的大量争用是不能满足速度需要的,Linux中是在遍历树的时候采用一种RCU技术,来实现同步并发。
RCU(Read-Copy Update),是一种保证读该radix tree的时候,可以不要管insert/delete操作,即不需使用锁。从内核代码来看,lookup操作的时候,读一个节点的时候,采用类似于 node = rcu_dereference(*slot); 的调用。Insert/delete操作指针的时候,采用
rcu_assign_pointer(node->slots[offset], slot); 的调用。具体同步的事情都交给RCU去搞的。
通过使用RCU,RCU Radix树可以进行完全并发的查询操作。RCU从根本上要求原子操作地移动指针从数据结构的一个版本到新的版本,保持旧版本直到系统经过静止状态。在静止状态点,旧版本数据结构已没有用户,因此可以被安全释放。
RCU radix树的修改操作之间还需要串行化,但是查询不再需要与修改操作串行化。
RCU可使RCU radix树查询完全并行化,但修改操作成了“瓶颈”。这可通过将全树的锁破碎成较小的锁进行改善,再明显的方法是对结点进行加锁而非对整个树加锁。
radix树修改操作可分为单向和双向操作。单向操作仅执行从根节点和叶子结点的单方向指针移动,它包括插入、更新和设置标签操作。双向操作较复杂,它需要在指针移到叶子后又回移,它包括删除和清除标签操作。
梯级加锁(Ladder Locking)和锁耦合(Lock-Coupling)技术常用于数据库方面,允许单向遍历结点加锁的树(双向可能产生死锁)。如果所有的修改者从树顶到树底进行修改,并且修改的结点持有锁,那么,向下遍历时对孩子加锁,在孩子被锁住时再释放该结点锁。在这种情况下并发操作是可能的,因为只要根结点解锁,另一个操作就可以自上向下进行。如果两操作的路径没有相同操作结点,后一个操作可能在前一个操作完成之前完成。最坏的情况是流水线操作,但这还是比串行化操作好很多。
双向操作包括删除和清除标签操作,分别说明如下:
8.1清除标签
在radix树中清除一个标签包括向下遍历树、查找定位条目和清除条目标签的操作。只要孩子结点没有打标签的条目,就可以向上遍历结点清除标签。结束条件是:如果遍历遇到一个结点,在清除一个标签后,它还有一个或多个条目带有标签集,就可以结束向上遍历。为了与向下遍历期间有同样的结束点,将终止条件改为:向上遍历将在有比清除标签数更多标签的结点处结束。这样,不论何时遇到这样的结点,将作为上遍历树的结束点。
8.2删除元素
删除元素在删除无用结点时还需要删除该条目的所有标签。它的终止条件需要满足这两个方面。向上回退遍历树时需要满足下面的条件:当遇到一个非空结点且没有无用的标签时应终止向上回退遍历树。
在向下遍历树时鉴别此点的条件是:当遇到有超过2个孩子的结点、并且每个标签来说结点有多于一个标签条目被清除时,结束向上遍历。该条件用来鉴别向上回退遍历的终止点。
8.3并行操作的API实现:查询获取slot操作
查询操作支持RCU无阻塞并行读操作,因此,需要遵循RCU的用法加RCU读锁,还需要将rcu_dereference()用于获得的slot,在写(或更新)操作时,需要给新的slot使用rcu_assign_pointer()。查询操作的使用方法列出如下:
struct page **slot, *page;
rcu_read_lock();
slot = radix_tree_lookup_slot(&mapping->page_tree, index);
page = rcu_dereference(*slot);
rcu_read_unlock();
8.4并行操作的API实现:查询修改slot操作
Linux内核的radix树需要打补丁才支持并发修改。查询仅有一个全局状态:RCU静止状态,并发修改需要跟踪持有什么锁。锁状态对于操作来说必须是外部的,因此,我们需要实例化一个本地上下文跟踪这些锁。查询修改slot的方法列出如下:
struct page **slot;
DEFINE_RADIX_TREE_CONTEXT(ctx,&mapping->page_tree);
radix_tree_lock(&ctx); /*锁住了根结点*/
/* ctx.tree代替&mapping->page_tree作为根,可以传递上下文
slot = radix_tree_lookup_slot(tx.tree, index);
rcu_assign_pointer(*slot, new_page);
radix_tree_unlock(&ctx);
radix树API函数radix_tree_lookup_slot含有锁从树顶向下移动机制,锁移动的代码部分列出如下:
void **radix_tree_lookup_slot(struct
radix_tree *root, unsigned long index)
{
...
RADIX_TREE_CONTEXT(context, root); /*提供上下文和实际的root指针*、
...
do {
...
/* 从树顶向下移动锁*/
radix_ladder_lock(context, node);
...
} while (height > 0);
...
}
2.
其他注意点
间接指针和直接指针
在真实环境中,地址都是字节对齐的,所以不存在最后一位为1的情况。那么就可以用地址的最后一位来标识一些有用的信息:标识为0则意味着该节点是直接节点,直接指向item数据,反之则则为间接节点,指向的是下一层节点。
#define RADIX_TREE_INDIRECT_PTR 1
//把最后一位值为1
static inline void
*radix_tree_ptr_to_indirect(void *ptr)
{ return
(void *)((unsigned long)ptr | RADIX_TREE_INDIRECT_PTR); }
//把最后一位值为0
static inline void
*radix_tree_indirect_to_ptr(void *ptr)
{ return
(void *)((unsigned long)ptr & ~RADIX_TREE_INDIRECT_PTR); }
//判断是否是间接节点
static inline int
radix_tree_is_indirect_ptr(void *ptr)
{ return
(int)((unsigned long)ptr & RADIX_TREE_INDIRECT_PTR); }
Linux内核Radix Tree(二)的更多相关文章
- Linux内核Radix Tree(一)
一.概述 Linux radix树最广泛的用途是用于内存管理,结构address_space通过radix树跟踪绑定到地址映射上的核心页,该radix树允许内存管理代码快速查找标识为dirty或wri ...
- Linux内核Radix Tree(三):API介绍
1. 单值查找radix_tree_lookup 函数radix_tree_lookup执行查找操作,查找方法是:从叶子到树顶,通过数组索引键值值查看数组元素的方法,一层层地查找slot.其列 ...
- Linux内核分析(二)----内核模块简介|简单内核模块实现
原文:Linux内核分析(二)----内核模块简介|简单内核模块实现 Linux内核分析(二) 昨天我们开始了内核的分析,网上有很多人是用用源码直接分析,这样造成的问题是,大家觉得很枯燥很难理解,从某 ...
- Linux内核学习笔记二——进程
Linux内核学习笔记二——进程 一 进程与线程 进程就是处于执行期的程序,包含了独立地址空间,多个执行线程等资源. 线程是进程中活动的对象,每个线程都拥有独立的程序计数器.进程栈和一组进程寄存器 ...
- linux内核学习之二 一个精简内核的分析(基于时间片轮转)
一 实验过程及效果 1.准备好相关的代码,分别是mymain.c,mypcb.h,myinterrupt.c ,如下图,make make成功: 在qemu创建的虚拟环境下的运行效果:(使用的命令 ...
- Linux内核分析作业二—操作系统是如何工作的
一.实验:简单的时间片轮转多道程序内核代码运行与分析 my_start_kernel之前都是硬件初始化,它是操作系统的执行入口,每循环100000次就进行一次打印. 执行更加简单,每次时钟中断时都会调 ...
- linux内核分析实践二学习笔记
Linux实践二--内核模块的编译 标签(空格分隔): 20135328陈都 理解内核的作用 Linux内核[kernel]是整个操作系统的最底层,它负责整个硬件的驱动,以及提供各种系统所需的核心功能 ...
- “Linux内核分析”实验二报告
张文俊 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.第二周学习内 ...
- Linux内核分析 笔记二 操作系统是如何工作的 ——by王玥
一.知识要点 1.计算机是如何工作的?(总结)——三个法宝 存储程序计算机工作模型,计算机系统最最基础性的逻辑结构: 函数调用堆栈,高级语言得以运行的基础,只有机器语言和汇编语言的时候堆栈机制对于计算 ...
随机推荐
- View绘制详解(二),从setContentView谈起
掐指一算,本来今天该介绍View的测量了,可是要说View的测量,那就要从setContentView谈起了,setContentView本身涉及到的东西也是挺多的,所以今天我们就先来看看这个setC ...
- Android_AsyncTask_Method
package com.example.day07_asynctask_method; import android.os.AsyncTask; import android.os.Bundle; i ...
- posix thread互斥量
互斥量 互斥量(Mutex)是“mutual exclusion”的缩写.互斥量是实现线程同步,和保护同时写共享数据的主要方法.使用互斥量的典型顺序如下:1. 创建和初始一个互斥量 2. 多个线程尝试 ...
- JavaScript中的作用域与函数和变量声明的提升
var foo = 1; function bar() { if (!foo) { var foo = 10; } alert(foo); } bar(); ...
- 3.x vector的用法
#include<vector> //struct struct GOLD_STRUCT { Sprite * goldspSprite; int goldValue; ...
- adb uninstall卸载apk 命令后跟的是包的名称
昨天在使用adb卸载程序,结果死活卸载不了.我输入的命令和系统提示如下: arthur@arthur-laptop:~$ adb uninstall com.hase.bclm.client-2.ap ...
- Bootstrap--组件之Glyphicons字体图标
Glyphicons 字体图标 所有可用的图标 包括250多个来自 Glyphicon Halflings 的字体图标.Glyphicons Halflings 一般是收费的,但是他们的作者允许 Bo ...
- UIButton关于setFont方法过时的解决方法
环境:xcode7 语言:Object-c 解决方法:更改UIButton的titleLabel属性的font值 一.新建一个Single View Application项目 二.创建一个UIBut ...
- iOS中 常用的mac终端指令
1.使用caffeinate阻止Mac运行屏幕保护和睡眠 caffeinate能阻止Mac进入睡眠状态,而且屏幕保护也不会激活.我们最好使用-t为命令加入具体的时间.比如下面的命令可以使Mac一小时内 ...
- 懒人记录 Hadoop2.7.1 集群搭建过程
懒人记录 Hadoop2.7.1 集群搭建过程 2016-07-02 13:15:45 总结 除了配置hosts ,和免密码互连之外,先在一台机器上装好所有东西 配置好之后,拷贝虚拟机,配置hosts ...