读APUE分析散列表的使用
最近学习APUE读到避免线程死锁的部分,看到部分源码涉及到避免死锁部分,源码使用了散列表来实现对结构(struct)的存储与查找。
本文不讨论代码中的互斥量部分。
#include <stdlib.h>
#include <pthread.h> #define NHASH 29
#define HASH(id) (((unsigned long)id)%NHASH) struct foo *fh[NHASH]; pthread_mutex_t hashlock = PTHREAD_MUTEX_INITIALIZER; struct foo {
int f_count;
pthread_mutex_t f_lock;
int f_id;
struct foo *f_next; /* protected by hashlock */
/* ... more stuff here ... */
}; struct foo *
foo_alloc(int id) /* allocate the object */
{
struct foo *fp;
int idx; if ((fp = malloc(sizeof(struct foo))) != NULL) {
fp->f_count = ;
fp->f_id = id;
if (pthread_mutex_init(&fp->f_lock, NULL) != ) {
free(fp);
return(NULL);
}
idx = HASH(id);
pthread_mutex_lock(&hashlock);
fp->f_next = fh[idx];
fh[idx] = fp;
pthread_mutex_lock(&fp->f_lock);
pthread_mutex_unlock(&hashlock);
/* ... continue initialization ... */
pthread_mutex_unlock(&fp->f_lock);
}
return(fp);
} void
foo_hold(struct foo *fp) /* add a reference to the object */
{
pthread_mutex_lock(&fp->f_lock);
fp->f_count++;
pthread_mutex_unlock(&fp->f_lock);
} struct foo *
foo_find(int id) /* find an existing object */
{
struct foo *fp; pthread_mutex_lock(&hashlock);
for (fp = fh[HASH(id)]; fp != NULL; fp = fp->f_next) {
if (fp->f_id == id) {
foo_hold(fp);
break;
}
}
pthread_mutex_unlock(&hashlock);
return(fp);
} void
foo_rele(struct foo *fp) /* release a reference to the object */
{
struct foo *tfp;
int idx; pthread_mutex_lock(&fp->f_lock);
if (fp->f_count == ) { /* last reference */
pthread_mutex_unlock(&fp->f_lock);
pthread_mutex_lock(&hashlock);
pthread_mutex_lock(&fp->f_lock);
/* need to recheck the condition */
if (fp->f_count != ) {
fp->f_count--;
pthread_mutex_unlock(&fp->f_lock);
pthread_mutex_unlock(&hashlock);
return;
}
/* remove from list */
idx = HASH(fp->f_id);
tfp = fh[idx];
if (tfp == fp) {
fh[idx] = fp->f_next;
} else {
while (tfp->f_next != fp)
tfp = tfp->f_next;
tfp->f_next = fp->f_next;
}
pthread_mutex_unlock(&hashlock);
pthread_mutex_unlock(&fp->f_lock);
pthread_mutex_destroy(&fp->f_lock);
free(fp);
} else {
fp->f_count--;
pthread_mutex_unlock(&fp->f_lock);
}
}
代码来自:http://blog.csdn.net/abcef31415926/article/details/53898325
取余法散列表:书中使用的是取余法来构建散列表,通过使用第5行定义的宏函数来计算(唯一计算)出每个ID(struct内部属性,保证struct唯一性)对应的散列表中的直接索引值。
而对于一个本例中已经构建出来的散列表,它的本质是这样的:

上图的0-15的实现实质其实也是指针(有自己指向的对象的Value值),这也是我之前没有弄明白的地方。
之前一直以为散列表是一个链表(就是里面存了,n个指针,每个指针相互首尾串联)。
然而不然,散列表的每个元素都是一个链表的头指针(即假设0-15都不为空,则一个散列表有16个相互独立的链表),添加新结构进入散列表的方法则是将结构本身代替索引位置的头指针,并指向他。
代码分析(背景灰色部分):
4-5 :使用求余的方法构建散列函数,使得每一个ID都能通过散列函数计算出的值落中在散列表定义数组的索引区间内。
7:定义一个符合上述条件区间长度的数组,数组内的每个元素都是struct foo *类型,初始值为NULL。
foo_alloc(int id)部分:该函数的作用是在散列表中添加一个未初始化的id为id的新结构。
32:计算散列表中的索引(计算应该将新结构放在第几个链表里)。
34:将该结构的next节点指向目前该位置上链表的头结点。
35:将链表的头结点设置成自己的指针。
foo_find(int id)部分:该函数的作用是通过结构的id,在散列表中找到结构的指针。
58:通过散列函数计算出数组的索引值,并确保在该索引位置上的链表中从头到尾使用循环查找。
59-63:如果链表中的某个结点满足id值和传入的id值相等的条件,就确信已经找到了该结构,返回这个指针。
foo_rele(struct foo *fp)部分:释放这个引用(指针),如果这是最后一个引用释放这个对象的内存空间。
75:如果这是当前的引用计数是1(该指针是最后一个指向对象的指针)。
87-88:通过散列函数计算索引,并获取链表第一个结点的地址。
89-91:如果当前结点是首结点,将链表的首指针(该位置的指针)设置为该元素的next指针。
92-95:向后寻找结点,直到该节点(结点a)的next是目标元素(结点b)的指针,把结点a的next设置为结点b的next。
99:该结点已经不在散列表内,释放对象的内存。
读APUE分析散列表的使用的更多相关文章
- Java HashMap源码分析(含散列表、红黑树、扰动函数等重点问题分析)
写在最前面 这个项目是从20年末就立好的 flag,经过几年的学习,回过头再去看很多知识点又有新的理解.所以趁着找实习的准备,结合以前的学习储备,创建一个主要针对应届生和初学者的 Java 开源知识项 ...
- 哈希表(散列表),Hash表漫谈
1.序 该篇分别讲了散列表的引出.散列函数的设计.处理冲突的方法.并给出一段简单的示例代码. 2.散列表的引出 给定一个关键字集合U={0,1......m-1},总共有不大于m个元素.如果m不是很大 ...
- 哈希表(散列表)—Hash表解决地址冲突 C语言实现
哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.具体的介绍网上有很详 ...
- 散列表(hash table)——算法导论(13)
1. 引言 许多应用都需要动态集合结构,它至少需要支持Insert,search和delete字典操作.散列表(hash table)是实现字典操作的一种有效的数据结构. 2. 直接寻址表 在介绍散列 ...
- HashTable(散列表)
最近都在研究数据结构,关于hashtable,或者叫做散列表,过去一直不了解是什么东西,现在终于明白了. 所谓hashtable,就是某组key,通过某个关系(函数),得到一个与之对应的映射值(在计算 ...
- &11,散列表
#1,是什么? 散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个 ...
- [转载] 散列表(Hash Table)从理论到实用(上)
转载自:白话算法(6) 散列表(Hash Table)从理论到实用(上) 处理实际问题的一般数学方法是,首先提炼出问题的本质元素,然后把它看作一个比现实无限宽广的可能性系统,这个系统中的实质关系可以通 ...
- Java学习笔记(二十)——Java 散列表_算法内容
[前面的话] 周末,本来打算找人去玩,结果没找到,所以我只好有学习了. 为什么会学习散列表,因为要使用HashMap?因为在做项目的时候,在服务器和客户端需要传输DTO,而传输的属性是动态增加的,所以 ...
- 散列表 (Hash table,也叫哈希表)
散列表是根据关键字(Key value)而直接访问在内存存储位置的数据结构.也就是说,它通过把键值通过一个函数的计算,映射到表中一个位置来访问记录,这加快了查找速度.这个映射函数称做散列函数,存放记录 ...
随机推荐
- ServletConfig使用
一.ServletConfig讲解 1.1.配置Servlet初始化参数 在Servlet的配置文件web.xml中,可以使用一个或多个<init-param>标签为servlet配置一些 ...
- ASP.NET脚本过滤-防止跨站脚本攻击(收集别人的)
ASP.Net 1.1后引入了对提交表单自动检查是否存在XSS(跨站脚本攻击)的能力.当用户试图用<xxxx>之类的输入影响页面返回结果的时候,ASP.Net的引擎会引发一个 HttpRe ...
- Docker 使用指南 (四)—— 数据卷的使用
一.数据卷的使用 有时候需要使用数据库,但是又希望它的数据能保存在本地,Docker中提供了数据卷可以供你方便的操作数据.数据卷是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用 ...
- 安装vnc远程连接CentOS桌面
1.查看本机是否有安装vnc(centOS5默认有安装vnc) rpm -q vnc vnc-server 如果显示结果为: package vnc is not installedvnc-serve ...
- Linux下安装Java(JDK8)
一.文件准备 1.1 文件名称 jdk-8u121-linux-x64.tar.gz 1.2 下载地址 http://www.oracle.com/technetwork/java/javase/do ...
- WPF+AE开发小结--TOCControl右键菜单删除图层
1.WPF项目中添加toccontrol控件,如何添加,网上有很多方法,可自行搜索,这里不再赘述,代码如下 <Window x:Class="AE.MainWindow" x ...
- 解决Highcharts 5.0.7,IE8下bar类型图表无法显示的问题
引用如上, 当图标类型为bar时,IE8无法直接显示, 官网也一样, 但通过切换图例可以显示, 所以加入以下代码解决此问题 未经允许,严禁转载!!!
- 数据结构(三) 用java实现七种排序算法。
很多时候,听别人在讨论快速排序,选择排序,冒泡排序等,都觉得很牛逼,心想,卧槽,排序也分那么多种,就觉得别人很牛逼呀,其实不然,当我们自己去了解学习后发现,并没有想象中那么难,今天就一起总结一下各种排 ...
- cephfs创建及挂载
Ceph 文件系统( Ceph FS )是个 POSIX 兼容的文件系统,它使用 Ceph 存储集群来存储数据.Ceph 文件系统要求 Ceph 存储集群内至少有一个 Ceph 元数据服务器. 1.添 ...
- 性能调优之剖析OutOfMemoryError
性能调优之剖析OutOfMemoryError poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询q ...