读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)而直接访问在内存存储位置的数据结构.也就是说,它通过把键值通过一个函数的计算,映射到表中一个位置来访问记录,这加快了查找速度.这个映射函数称做散列函数,存放记录 ...
随机推荐
- .NET的HTTP辅助类:RestSharp
示例: var client = new RestClient("http://example.com");// client.Authenticator = new HttpBa ...
- Codeforces Gym 100269E Energy Tycoon 贪心
题目链接:http://codeforces.com/gym/100269/attachments 题意: 有长度为n个格子,你有两种操作,1是放一个长度为1的东西上去,2是放一个长度为2的东西上去 ...
- java根据HashMap中的值将其元素排序
思路:HashMap或Map本身没有排序功能,若要进行较轻松的排序,可利用ArrayList中的sort方法 例子: import java.util.ArrayList; import java.u ...
- 《用Python做HTTP接口测试》学习感悟
机缘巧合之下,报名参加了阿奎老师发布在"好班长"的课程<用Python做HTTP接口测试>,报名费:15rmb,不到一杯咖啡钱,目前为止的状态:坚定不移的跟下去,自学+ ...
- Tcl与Design Compiler (四)——DC启动环境的设置
本文属于原创手打(有参考文献),如果有错,欢迎留言更正:此外,转载请标明出处 http://www.cnblogs.com/IClearner/ ,作者:IC_learner 主要内容有: ·启动环 ...
- python文件读写出现乱码总结
1.错误的打开方式 #coding=utf-8f = open("test.txt",'w+')f.write('Mars is slim,isn\'he? \n 火星教')pri ...
- AutoMapper.RegExtension[.NET Core版本] 介绍
Technorati 标签: AutoMapper.RegExtension,AutoMapper.RegExtension .NET CORE AutoMapper.RegExtension 为一个 ...
- 当在浏览器地址栏里输入URL后会发生什么事情
其实这个很多大神已经说的很多了.但是为了自己更好的理解,在自己所接触的层面上,重新对自己讲解一下.当然,这是站在一个前端开发者的角度上来看问题的. 说说一次HTTP完整事务的过程 输入URL 浏览器从 ...
- PRINCE2的国际形势?光环国际项目管理培训
PRINCE2的使用和应用非常广泛.在过去的12个月里,超过60,000人参加了PRINCE2基础资格(Foundation)或从业资格(Practitioner)考试.现在每周参加考试的人数超过了2 ...
- 20155206 2016-2017-2 《Java程序设计》第5周学习总结
20155206 2016-2017-2 <Java程序设计>第5周学习总结 教材学习内容总结 Java中所有错误都会被打包为对象,运用try.catch,可以在错误发生时显示友好的错误信 ...