博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
读APUE分析散列表的使用
阅读量:4654 次
发布时间:2019-06-09

本文共 4324 字,大约阅读时间需要 14 分钟。

最近学习APUE读到避免线程死锁的部分,看到部分源码涉及到避免死锁部分,源码使用了散列表来实现对结构(struct)的存储与查找

本文不讨论代码中的互斥量部分。

 

1 #include 
2 #include
3 4 #define NHASH 29 5 #define HASH(id) (((unsigned long)id)%NHASH) 6 7 struct foo *fh[NHASH]; 8 9 pthread_mutex_t hashlock = PTHREAD_MUTEX_INITIALIZER; 10 11 struct foo { 12 int f_count; 13 pthread_mutex_t f_lock; 14 int f_id; 15 struct foo *f_next; /* protected by hashlock */ 16 /* ... more stuff here ... */ 17 }; 18 19 struct foo * 20 foo_alloc(int id) /* allocate the object */ 21 { 22 struct foo *fp; 23 int idx; 24 25 if ((fp = malloc(sizeof(struct foo))) != NULL) { 26 fp->f_count = 1; 27 fp->f_id = id; 28 if (pthread_mutex_init(&fp->f_lock, NULL) != 0) { 29 free(fp); 30 return(NULL); 31 } 32 idx = HASH(id); 33 pthread_mutex_lock(&hashlock); 34 fp->f_next = fh[idx]; 35 fh[idx] = fp; 36 pthread_mutex_lock(&fp->f_lock); 37 pthread_mutex_unlock(&hashlock); 38 /* ... continue initialization ... */ 39 pthread_mutex_unlock(&fp->f_lock); 40 } 41 return(fp); 42 } 43 44 void 45 foo_hold(struct foo *fp) /* add a reference to the object */ 46 { 47 pthread_mutex_lock(&fp->f_lock); 48 fp->f_count++; 49 pthread_mutex_unlock(&fp->f_lock); 50 } 51 52 struct foo * 53 foo_find(int id) /* find an existing object */ 54 { 55 struct foo *fp; 56 57 pthread_mutex_lock(&hashlock); 58 for (fp = fh[HASH(id)]; fp != NULL; fp = fp->f_next) { 59 if (fp->f_id == id) { 60 foo_hold(fp); 61 break; 62 } 63 } 64 pthread_mutex_unlock(&hashlock); 65 return(fp); 66 } 67 68 void 69 foo_rele(struct foo *fp) /* release a reference to the object */ 70 { 71 struct foo *tfp; 72 int idx; 73 74 pthread_mutex_lock(&fp->f_lock); 75 if (fp->f_count == 1) { /* last reference */ 76 pthread_mutex_unlock(&fp->f_lock); 77 pthread_mutex_lock(&hashlock); 78 pthread_mutex_lock(&fp->f_lock); 79 /* need to recheck the condition */ 80 if (fp->f_count != 1) { 81 fp->f_count--; 82 pthread_mutex_unlock(&fp->f_lock); 83 pthread_mutex_unlock(&hashlock); 84 return; 85 } 86 /* remove from list */ 87 idx = HASH(fp->f_id); 88 tfp = fh[idx]; 89 if (tfp == fp) { 90 fh[idx] = fp->f_next; 91 } else { 92 while (tfp->f_next != fp) 93 tfp = tfp->f_next; 94 tfp->f_next = fp->f_next; 95 } 96 pthread_mutex_unlock(&hashlock); 97 pthread_mutex_unlock(&fp->f_lock); 98 pthread_mutex_destroy(&fp->f_lock); 99 free(fp); 100 } else { 101 fp->f_count--; 102 pthread_mutex_unlock(&fp->f_lock); 103 } 104 }

代码来自: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:该结点已经不在散列表内,释放对象的内存。

posted on
2017-04-28 10:13  阅读(
...) 评论(
...) 收藏

转载于:https://www.cnblogs.com/TsAihS/p/6780182.html

你可能感兴趣的文章
Flex【原创】移动设备相册图片浏览功能
查看>>
Nodejs on windows 10
查看>>
HDU1233--还是畅通工程(最小生成树)
查看>>
linux——实际工作中如何使用linux
查看>>
设置 jsp 表格相邻两行的颜色不一样
查看>>
性能指标分析
查看>>
Jenkins企业应用
查看>>
[POJ 1061]青蛙的约会
查看>>
使用SeaJS实现模块化JavaScript开发
查看>>
开源项目如何赚钱
查看>>
BZOJ 1260 [CQOI2007]涂色paint(区间DP)
查看>>
HDU 1005 Number Sequence
查看>>
7 种将字符串反转的 Java 方法
查看>>
Softmax函数
查看>>
【题解】贪婪大陆
查看>>
notepad ++ 编辑 powershell profile 文件时的诡异问题
查看>>
这是一个测试文章
查看>>
struts2——文件下载(简单的功能)
查看>>
Java Bean Validation 最佳实践
查看>>
2018的第二篇博客 关于SSH框架的注解版整合
查看>>