多執行緒操作雜湊表避免死鎖
阿新 • • 發佈:2019-01-05
copy自《UNIX環境高階程式設計》圖11.11。
#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 = 1;
fp->f_id = id;
if (pthread_mutex_init(&fp->f_lock, NULL) != 0) {
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 == 1) { /* 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 != 1) {
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);
}
}
程式基本流程:
fh 雜湊表(連結串列解決雜湊衝突)
foo 雜湊表節點(指向物件)
foo_alloc 申請節點
1、申請節點記憶體
2、插入到雜湊表
2.1、雜湊表加鎖(hashlock)
2.2、插入新節點
2.3、節點加鎖(此時節點已經新增到雜湊表中了)
2.4、雜湊表解鎖
2.5、其他初始化動作
2.6、節點解鎖
foo_hold 拿住節點
1、節點加鎖(所有節點都應該是通過foo_alloc獲取的,所以使用的時候已經在雜湊表中了)
2、節點引用計數加1
2、節點解鎖
foo_find 查詢節點
1、雜湊表加鎖(避免此時有申請或者釋放節點)
2、查詢節點
3、雜湊表解鎖
foo_rele 釋放節點
1、節點加鎖
2、判斷節點引用計數是否為1
2.1、節點引用計數為1,做以下動作
a. 節點解鎖,雜湊表加鎖
b. 節點加鎖
判斷此時節點引用計數是否為1,不為1則將引用計數減1
然後解鎖節點、解鎖雜湊表,函式返回
c. 從雜湊表中移除節點
d. 雜湊表解鎖
e. 節點解鎖
f. 釋放節點記憶體(需要釋放鎖)
2.2、節點引用計數不為1
節點引用計數減1
節點解鎖
foo_rele:
參考: