风险指针(Hazard Pointer) 内存空间共享模型
WiredTiger是一种高性能的开源存储引擎,现已在MongoDB中作为内模式应用。WiredTiger支持行存储、列存储两种存储模式,采用LSM Tree方式进行索引记录
WiredTiger支持事务的ACID特性(原子性、一致性、隔离性、持久性)。对数据的存储方式可采用简易的key/value形式进行存储,也可以使用包含索引映射的数据模式层的方式进行存储。
WiredTiger存储引擎可应用于现代多核CPU架构之上。采用多种实现方式,如风险指针(hazard pointers)、无锁算法(lock-free algorithms)、快锁(fast latching)、消息传递(message passing)等方法。
风险指针(Hazard Pointers)
风险指针是一种内存管理的方法,允许内存被回收后任意重用。该内存管理方法是无等待的(wait-free)。核心操作仅需要单字的内存读取和写入访问。该方法同样提供了ABA问题的一个无锁解决方案。对于指针的管理,通常关注与如何回收已经删除掉的对象所占用的内存。在基于锁的对象的情形下,当线程从对象中删除一个节点时,在它被重用或者重新分配之前,很容易保证没有其他线程会在此后访问该节点的内存。但在无锁动态对象就出现了问题。为了保证无锁的对象的顺利执行,每个线程必须要有无限制的机会在任意时间操作该对象。
内存回收问题是如何允许被删除节点的内存被释放,同时还保证没有线程访问被释放的内存,以及如何以一种无锁的方式做到这一点。之前的用以动态无锁对象的节点重用方法主要有三种:
- IBM标签方法(更新计数)
- 无锁引用计数
- 基于总体引用计数或者每个线程的时间戳方法
风险指针,是一种以无锁对象的内存回收方法。它对每个被删除的节点的分摊时间是预期的常量。无论线程是失败还是延迟,它都能对不可重用的被删除节点的总数保持一个上界。其核心思想是:将一些被称为风险指针(hazard pointer)的单写者多读者的共享指针,与每个想要访问无锁对象的线程关联起来。一个风险指针要么是NULL,要么指向一个节点,该节点之后可能会被该线程访问,而不需要验证对该节点的这个引用是否有效。每个风险指针只能被其拥有者线程写入,但是可以被别的线程读取。
基础模型
基本计算模型是异步共享内存模型。在该模型中一组线程通过在一组共享内存位置上的内存访问操作原语来沟通。线程运行在任意速度,可以有任意延迟。线程对任何其他线程的速度或状态不做任何假设。
共享对象占有一组共享内存位置。对象是一个抽象的对象类型实现的实例,它定义了在对象上可以允许的操作的语义。
原子原语
除了读取和写入外,共享内存位置上的基本操作还包括CAS(compare-and-swap)和load-linked/store-conditional(LL/SC)。
CAS有三个参数:内存位置的地址、预期值、新值。当且仅当存储单元存储的是预期值的时候,新值才能原子地写入该存储单元。该操作返回一个布尔值,用以表示是否发生了写操作。
LL需要一个参数:内存位置的地址,该操作将返回其内容。SS有两个参数:一个内存位置的地址和一个新值。只有当前线程最后使用LL读取该位置之后,没有其他线程写入该内存位置,新值才会原子地写入到该内存位置的地址,并返回一个布尔值,指示自从当前线程最后使用LL读取该位置之后是否有任何其他线程写入过该内存位置。
ABA问题
问题描述如下:它发生在当一个线程从共享位置读取值A,然后其他线程改变该位置为不同的值,例如B。当该线程再次将A放回该共享位置处时,新的线程再次从该位置读取该共享位置处的值时,会误认为该值没有改变,从而错误的执行。
Hazard Pointer要解决的核心问题是如何安全释放内存,该问题解决在实现无锁算法时有两个关键的影响:
- 保证了关键节点的访问是合法的,不会导致程序尝试去读取已经释放了的内存。
- 保证了ABA问题不会出现,程序逻辑正确的前提。
无锁算法中释放内存的难点在于当线程释放了一块内存后,是无法获知是否有别的线程也同时持有该块内存的指针并需要访问。
解决方案
- 建立一个全局数组,数组容量为线程数目,每个线程只能修改自己的数组元素,而不允许修改其他的数组元素,但可以读别的数组元素。
- 当线程尝试访问一个关键数据节点时,先把该节点指针赋给自己的数组元素(即不要释放这个节点)。
- 每个线程自己维护一个私有链表,当线程准备释放掉某个节点时,将该节点放入到链表中。当链表内的数目达到一个设定的数目后,遍历该链表用于释放链表内所有节点。
- 当释放节点时,需要检查全局数组,确定没有任何一个线程的数组元素与当前指针相同时,就释放该节点。否则仍然滞留在自己的链表中。
Hazard Pointer主要应用在实现无锁队列上。
- 队列上的元素任何时候,只可能被其中一个线程成功地从队列上取下来,因此每个线程的链表中的元素肯定是唯一的。
- 线程在操作无锁队列时,任何时候基本只需要处理一个节点,如果有特殊需求,就需要有额外的扩展
- 对于某个节点,多线程同时持有该节点的指针的现象在时间上是非常短暂的。只有当这几个线程同时尝试取下该节点,它们才可能同时持有该节点的指针,一旦某线程成功将节点取下,其它线程很快就会发现,并尝试继续操作下一个节点。
风险指针(Hazard Pointer) 内存空间共享模型的更多相关文章
- 在64位系统下,指向int型的指针占的内存空间多大?
不废话,请看代码演示如下: 注意使用的操作系统的位数,不同位数的操作系统,结果不一样! 我是用的是64位的操作系统! linux下示例代码如下: #include <stdio.h> in ...
- C语言指针及占据内存空间
第一.了解内存空间 本文章文字有点多,会有点枯燥,配合图文一起看可以缓解枯燥,耐心阅读哦!!! 先了解内存地址,才更好的理解指针! 我们可以把内存想象为成一列很长很长的货运火车,有很多大小相同的车厢, ...
- C语言中指针占据内存空间问题
以前一直有个疑问,指向不同类型的指针到底占用的内存空间是多大呢? 这个问题我多次问过老师,老师的答案是"指向不同类型的指针占据的内存空间大小不同",我一直很之一这个答案,今天我就做 ...
- 《C和指针(Pointer on c)》 学习笔记(转自:http://dsqiu.iteye.com/blog/1687944)
首先本文是对参考中三个连接的博客进行的整理,非常感谢三位博主的努力,每次都感叹网友的力量实在太强大了…… 第一章 快速上手 1. 在C语言中用/*和*/来注释掉这段代码,这个实际上并不是十分的安全, ...
- 《C和指针(Pointer on c)》 学习笔记
转载:http://dsqiu.iteye.com/blog/1687944 首先本文是对参考中三个连接的博客进行的整理,非常感谢三位博主的努力,每次都感叹网友的力量实在太强大了…… 第一章 快速上手 ...
- C++二级指针第二种内存模型(二维数组)
C++二级指针第二种内存模型(二维数组) 二维数组 二维数组本质上是以数组作为数组元素的数组,即“数组的数组”. 定义 类型说明符 数组名[常量表达式][常量表达式] 例如: float a[3][4 ...
- lock free数据结构内存回收技术-hazard pointer
lock free数据结构一般来说拥有比基于lock实现的数据结构更高的性能,但是其实现比基于lock的实现更为复杂,需要处理的难题包括预防ABA问题,内存如何重用和回收等.通常,最简单最有效的处理A ...
- C++二级指针第一种内存模型(指针数组)
二级指针第一种内存模型(指针数组) 指针的输入特性:在主调函数里面分配内存,在被调用函数里面使用指针的输出特性:在被调用函数里面分配内存,主要是把运算结果甩出来 指针数组 在C语言和C++语言中,数组 ...
- C/C++ 错误笔记-在给结构体中的指针赋值时,要注意该指针是否已指向内存空间
先来看下面的例子: #include <stdlib.h> #include <string.h> #include <stdio.h> #pragma warni ...
随机推荐
- 面试基础知识集合(python、计算机网络、操作系统、数据结构、数据库等杂记)
python python _.__.__xx__之间的差别 python中range.xrange和randrange的区别 python中 =.copy.deepcopy的差别 python 继承 ...
- GO入门——2. 变量
1 基本类型 零值并不等于空值,而是当变量被声明为某种类型后的默认值, 通常情况下值类型的默认值为0,bool为false,string为空字符串,引用为nil. 1.1 布尔类型 关键字:bool ...
- Python学习--11 面向对象高级编程
多重继承 Python里允许多重继承,即一个类可以同时继承多个类: class Mammal(Animal): pass class Runnable(object): def run(self): ...
- IDA动态调试so文件出现SIGILL
用ida6.6 调试android的so文件时经常会报SIGILL的错误,意思是指令非法.而且这种错误基本都是发生在系统函数内部,像我遇到过的mmap,fopen,fgets等等.在这些函数内部如果用 ...
- vue-cli 使用better-scroll
better-scroll api文档https://ustbhuangyi.github.io/better-scroll/doc/zh-hans/ 一:安装better-scroll 插件 cn ...
- ASP.NET MVC5+EF6+LayUI实战教程,通用后台管理系统框架(4)- 漂亮的登录界面
前言 这一讲,给大家添加登录页面 实现 添加Login的Index视图 @{ Layout = null; } <!DOCTYPE html> <html class="l ...
- springboot自定义静态文件目录,解决jar打包后修改页面等静态文件的问题
1.问题 springboot开发时候,一般将文件放在resources目录,但是发布后想修订文件或是开发时候修改了文件内容一般需重新打包或者重启动才能达到效果: 2.原因 将资源文件打包入jar包, ...
- OpenGL学习笔记:Console工程下如何不显示控制台黑窗口只显示Windows窗口
刚学习OpenGL,绘制图形的时候,如果不进行设置,运行的时候会先出现黑窗口再出现Windows窗口. 其实要去除控制台窗口非常简单,只需要修改工程设置,把子系统改成Windows,程序的入口点改成m ...
- [日常] Go语言圣经--结构体,JSON习题
Go语言圣经-结构体 1.结构体是一种聚合的数据类型,是由零个或多个任意类型的值聚合成的实体 2.通常一行对应一个结构体成员,成员的名字在前类型在后,不过如果相邻的成员类型如果相同的话可以被合并到一行 ...
- 2.移植3.4内核-支持烧写yaffs2,裁剪内核并制作补丁
在上章-制作文件系统,并使内核成功启动jffs2文件系统了 本章主要内容如下: 1)使内核支持yaffs2文件系统 2)裁剪内核 3)制作内核补丁 1.首先获取yaffs2源码(参考git命令使用详解 ...