风险指针(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 ...
随机推荐
- (转载)es进行聚合操作时提示Fielddata is disabled on text fields by default
原文地址:http://blog.csdn.net/u011403655/article/details/71107415 根据es官网的文档执行 GET /megacorp/employee/_se ...
- CentOS7系统下YUM安装安装Mongodb 3.4
第一步 查看是否存在Mongodb配置yum源 切换到yum目录 cd /etc/yum.repos.d/ 查看文件 ls 第二部 不存在添加yum 源 创建文件 touch mongodb-3.4. ...
- Spring Boot 数据访问集成 MyBatis 与事物配置
对于软件系统而言,持久化数据到数据库是至关重要的一部分.在 Java 领域,有很多的实现了数据持久化层的工具和框架(ORM).ORM 框架的本质是简化编程中操作数据库的繁琐性,比如可以根据对象生成 S ...
- CFileDialog类的详情
CFileDialog类封装了Windows常用的文件对话框. 常用的文件对话框提供了一种简单的与Windows标准相一致的文件打开和文件存盘对话框功能. void CnotepadDlg::OnOp ...
- 解决Oracle死锁问题,及产生的原因
文章来源:http://www.cnblogs.com/leijh/archive/2012/10/15/2724165.html 最近老是发现应该执行操作数据库的代码时发现执行不了,查了一下发现是数 ...
- mycat中间件--linux安装mycat1.6版本
一.mycat安装前准备1.mycat下载地址,点击此处进行下载2.环境要求如下: mycat使用Java开发,因为用到了JDK 7的部分功能,所以在使用前请确保安装了JDK 7.0,并设置了正确的J ...
- webkit技术内幕读书笔记 (四)
资源缓存 资源缓存的目的是为了提高资源使用的效率,其基本思想是建立一个资源的缓存池,当需要请求资源的时候先去资源池查找是否有相应的资源,如果没有则向服务器发送请求,webkit收到资源后将其设置到该资 ...
- springboot-27-整合mybatis,druid连接池
sprinboot整合mybatis, 有2种方式, 第一种完全使用注解的方式, 还有一种就是使用xml文件的方式 项目使用gradle + idea, 数据源使用druid, 多使用groovy编写 ...
- U盘安装原版Win7或Win8教程
具体步骤: 1.先使用大白菜U盘启动制作工具制作完U盘启动(参照制作教程). 2.找到Windows7系统的iso镜像,用UltraISO或者WinRAR打开Win7的iso镜像,然后提取/解压所有文 ...
- js 之 this call apply
(一)关于this首先关于this我想说一句话,这句话记住了this的用法你也就差不多都能明白了:this指的是当前函数的对象.这句话可能比较绕,我会举出很多例子和这句话呼应的!(看下文)1.首先看下 ...