folly下AtomicHashArray和AtomicHashMap简介
来源:互联网 发布:python 关闭tcp连接 编辑:程序博客网 时间:2024/05/21 19:23
AtomicHashArray类
主要功能介绍:
主要有
std::atomic<int64_t> isFull_; // Used by insertInternal
std::atomic<int64_t> numErases_; // Successful key erases
std::atomic<KeyT> *cellkeyptr_; //cell中key的指针。
三种原子类型
维护一张哈希表的创建、插入、查询、删除(标记为erase并没有实际删除)。
哈希数据映射对,存放在cell_[]中,下标是通过hash算法计算出来的哈希值(具体插入位置还有可能通过probe线性探测位移得到)。
Cell[]中存放的是[Key,value]结构的pair。
Key只支持int型整数(使用其他类型可以先将其他类型转换为整数)。
引入原子操作,支持并发处理。
主要功能函数:
create()
申请哈希表所需的空间,初始化哈希表中的所有key为kEmptykey_。在初始化每个key值时,采用的是原子操作。(初始化用原子操作,难道会有多个线程同时初始化一个哈希表?)
findInternal ()
查询操作,最终所有的查询方式都会调用到此函数中,进行哈希查询。(查询操作应该不需要同步处理吧?)
根据key_in计算哈希下标。取下标中的key和key_in比较(取下标中对应的key用的是原子操作,这个原子操作是为了防止什么情况的发生?)。
如果key为kEmptyKey_,查询结果不存在。
如果key不为kEmptyKey_,且key和key_in相等,查找成功。
如果key不为kEmptyKey_,且key和key_in不相等,则线性遍历。直到上述情况出现,或者遍历结束都没找到。
erase ()
根据key_in计算哈希下标,原子操作取下标对应的key值(这个能解决什么冲突情况呢?)
判断取出的key值是否为kEmptyKey_或者kLockedKey(正在被插入)_。两种情况都说明key不存在。
如果key和key_in相等。原子操作将key设置为kErasedKey_(这个就算多线程同时设置为kErasedKey_会有问题吗?)。numErases_原子曾加1(这个方式多线程同时加出现的冲突问题)。此时只是将key标记为kErasedKey,并没有释放内存。主要原因是查询的时候将value指针给了用户,释放内存会出现野指针导致内核崩溃等问题。(这样的话,如果删除操作过于频繁的话,所需要的内存岂不是越来越大。这种处理方式不能够支持程序长期跑下去吧?)
如果key和key_in不相等。线性遍历。直到上述情况出现,或者遍历结束都没找到。
insertInternal()
插入操作最终都会调入到此函数中来,进行插入。
根据key_in计算哈希下标,原子操作取下标对应的key值,判断此key是否为kEmptyKey_
如果key为空,原子操作取isFull_,判断哈希表是否插满。
如果插满了,atomic_hash_spin_wait自旋锁等待其他正在插入的线程也都通过这里,然后设置isFull_为NO_PENDING_INSERTS,并返回插入失败,告诉AtomicHashMap此submap已经不能插入了。
如果没有满,则原子操作锁上当前的cell(保证只有一个进程能对这个cell进行插入操作,就看明白这个地方为什么用原子操作了,其他大多原子操作没看太懂是为了避免什么样的情况发生的)。插入操作结束后对cell解锁(上锁即将key设为lock状态,解锁就是将key插入新的key_in)。如果插入后已经插入的元素>=最大元素时,标记isFull_为true。
如果key不为空,cell还在被锁定,说明其他线程还在插入这个cell,等待其他线程插入完成。然后判断key和key_in是否相等
如果相等,本次插入失败,已经插入过。
如果不相等,如果key 为kEmptyKey_或者kLockedKey_说明之前有插入失败或还再插入的情况,那么continue等待。其他情况下进行线性遍历下一个cell。
AtomicHashMap类
主要功能:
主要有
std::atomic<SubMap*>subMaps_[kNumSubMaps_]; 指向AtomicHashArray
std::atomic<uint32_t> numMapsAllocated_; 记录AtomicHashArray数目
两种原子类型
AtomicHashMap主要用来对AtomicHashArray进行管理
主要功能函数:
AtomicHashMap ()
构造函数,初始化submap[0](原子操作,难道这个初始化也会交由多线程处理?),并初始化submap[subMapCount]后面的都指向空。
findInternal ()
首先原子操作获取subMaps_[0](获取操作有必要原子操作吗?),进行查询,如果没查询到,原子获取numMaps(Map数目),对只有的每个map进行依次查询,直到查到或者全部遍历或者没查到。
erase ()
原子操作依次加载每个map,进行查询删除操作。
insertInternal()
原子操作依次加载每个map,进行插入操作。如果全部插入满了,需要重新分配一个新的map进行插入操作。在重新分配时会调用atomic_hash_spin_wait(Cond condition)等待,分配好新的submap后再进行插入。
总结
对哈希表的操作主要还是在AtomicHashArray类中。根据上面的主要功能的分析情况,结合自己的想法:
1、 我觉得查询操作应该不需要同步机制,哈希表的多线程查询应该是没有问题的,没看懂AtomicHashArray中这句
const KeyT key =acquireLoadKey(cells_[idx]);
为什么需要原子操作取出下标对应的key?当然这样做也没什么错。
2、 erase()删除操作中,其实并不是我们传统的删除,只是将要删除的cell中的key值设置为erase标志来代表已经被删除掉了。但是实际上空间并没有释放,也不可能再次插入。这样的设定,对空间的要求应该很高吧,如果程序长期运行的话。
3、 insertInternal()插入过程中,也是除了在要对cell进行写入的时候应该上锁,别的地方,不用原子操作也是可以的吧,没看出来别的地方的原子操作时为了确保什么样的情况。
4、 其中锁的实现是使用此函数:
compare_exchange_strong(expect, kErasedKey_)) {
numErases_.fetch_add(1, std::memory_order_relaxed);
//当前值与期望值相等时,修改当前值为设定值,返回true
//当前值与期望值不等时,将期望值修改为当前值,返回false
//整个操作是原子的,在某个线程读取和修改该原子对象时,另外的线程不能对读取和修改该原子对象。
望有兴趣的朋友进行解答补充
- folly下AtomicHashArray和AtomicHashMap简介
- 今天try了下folly的small lock 很好
- folly->set_sorted_vector
- folly学习心得
- folly下stats中对最近时间段内数据的操作TimeseriesHistogram、BucketedTimeSeries、MultiLevelTimeSeries、HistogramBuckets
- ubuntu 编译folly库
- facebook folly 编译安装
- folly (facebook opensource library)
- Hyperpolyglots: Paragon or Folly?
- linux编译folly
- jboss下配置和部署EJB简介
- Linux下gcc简介和常用命令
- Android下am和pm命令简介
- facebook C++ overview(Folly)
- centos65 folly的编译安装
- JBoss3.0 下配置和部署EJB简介
- JBoss3.0 下配置和部署EJB简介
- JBoss3.0 下配置和部署EJB简介
- git checkout 时出现 error: pathspec '是0106' did not match any file(s) known to git.
- 时分秒针在一天之内重合多少次
- 2797: [Poi2012]Squarks
- java 实用函数汇总
- android 内存泄漏
- folly下AtomicHashArray和AtomicHashMap简介
- SSH的安装与配置 + WinSCP使用
- 【Linux必知必会】五种开源协议的比较(BSD,Apache,GPL,LGPL,MIT)
- android调用js需要注意的方式
- 信息检索(IR)的评价指标介绍 - 准确率、召回率、F1、mAP、ROC、AUC
- (1)uboot详解——板子刚上电时都干了些什么
- java源码中的nio包和I/O模型
- C#实现HTTP服务器
- Java读取文件txt里面的内容