最近学习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分析散列表的使用的更多相关文章

  1. Java HashMap源码分析(含散列表、红黑树、扰动函数等重点问题分析)

    写在最前面 这个项目是从20年末就立好的 flag,经过几年的学习,回过头再去看很多知识点又有新的理解.所以趁着找实习的准备,结合以前的学习储备,创建一个主要针对应届生和初学者的 Java 开源知识项 ...

  2. 哈希表(散列表),Hash表漫谈

    1.序 该篇分别讲了散列表的引出.散列函数的设计.处理冲突的方法.并给出一段简单的示例代码. 2.散列表的引出 给定一个关键字集合U={0,1......m-1},总共有不大于m个元素.如果m不是很大 ...

  3. 哈希表(散列表)—Hash表解决地址冲突 C语言实现

    哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.具体的介绍网上有很详 ...

  4. 散列表(hash table)——算法导论(13)

    1. 引言 许多应用都需要动态集合结构,它至少需要支持Insert,search和delete字典操作.散列表(hash table)是实现字典操作的一种有效的数据结构. 2. 直接寻址表 在介绍散列 ...

  5. HashTable(散列表)

    最近都在研究数据结构,关于hashtable,或者叫做散列表,过去一直不了解是什么东西,现在终于明白了. 所谓hashtable,就是某组key,通过某个关系(函数),得到一个与之对应的映射值(在计算 ...

  6. &11,散列表

    #1,是什么? 散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个 ...

  7. [转载] 散列表(Hash Table)从理论到实用(上)

    转载自:白话算法(6) 散列表(Hash Table)从理论到实用(上) 处理实际问题的一般数学方法是,首先提炼出问题的本质元素,然后把它看作一个比现实无限宽广的可能性系统,这个系统中的实质关系可以通 ...

  8. Java学习笔记(二十)——Java 散列表_算法内容

    [前面的话] 周末,本来打算找人去玩,结果没找到,所以我只好有学习了. 为什么会学习散列表,因为要使用HashMap?因为在做项目的时候,在服务器和客户端需要传输DTO,而传输的属性是动态增加的,所以 ...

  9. 散列表 (Hash table,也叫哈希表)

    散列表是根据关键字(Key value)而直接访问在内存存储位置的数据结构.也就是说,它通过把键值通过一个函数的计算,映射到表中一个位置来访问记录,这加快了查找速度.这个映射函数称做散列函数,存放记录 ...

随机推荐

  1. image图片拉伸

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px "PingFang SC"; color: #1d9421 } p.p2 ...

  2. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt".

    昨天遇到一个比较奇怪的问题,运行VS2010调试程序的时候,总是会报一个错,然后程序就挂掉了:无可用源….,弹出一个窗口提示:System.AccessViolationException: Atte ...

  3. (11)连个工具类之间的比较4.Collections与Arrays

    集合框架中的工具类:特点:该工具类中的方法都是静态的. Collections:常见方法: 1, 对list进行二分查找: 前提该集合一定要有序. int binarySearch(list,key) ...

  4. SQL Server中的Merge关键字 更新表数据

    简介 Merge关键字是一个神奇的DML关键字.它在SQL Server 2008被引入,它能将Insert,Update,Delete简单的并为一句.MSDN对于Merge的解释非常的短小精悍:”根 ...

  5. UWP Composition API - New FlexGrid 锁定行列

    如果之前看了 UWP Jenkins + NuGet + MSBuild 手把手教你做自动UWP Build 和 App store包 这篇的童鞋,针对VS2017,需要对应更新一下配置,需要的童鞋点 ...

  6. 查看apache,mysql,nginx,php的编译参数

    查看nginx编译参数:/usr/local/nginx/sbin/nginx -V 查看apache编译参数:cat /usr/local/apache2/build/config.nice 查看m ...

  7. java之泛型解说

    1.集合中只能装入引用数据类型,不能装入基本数据类型.如,装入int类型的数值123会自动装箱. 2.开发人员装入集合的数据类型不确定,所以它被设计成可以装入所有的Object. 3.新的问题产生,装 ...

  8. 参加光环国际PRINCE2培训

    挑战埃及是全球首套能够同时适配PRINCE2认证人群,PMP认证人群的项目管理沙盘演练游戏.沙盘通过使用乐高积木作为道具,通过一场互动性极强的情景模拟为全球项目经理还原了四千年前古埃及金字塔建造的情景 ...

  9. SPOJ - BITDIFF: Bit Difference [神妙の预处理]

    tags:[数学][预处理]题解:我们用一种巧妙的预处理姿势:记录下每一个数位上分别出现了多少个1.如果第i个数位上出现了cnt[i]个1,那么,在这个数位上产生的"差异值"为:2 ...

  10. VB6/VBA中跟踪鼠标移出窗体控件事件(类模块成员函数指针CHooker类应用)

    一.关于起因 前几天发了一篇博文,是关于获取VB类模块成员函数指针的内容(http://www.cnblogs.com/alexywt/p/5880993.html):今天我就发一下我的应用实例. V ...