1. 程式人生 > >多執行緒操作雜湊表避免死鎖

多執行緒操作雜湊表避免死鎖

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:

這裡寫圖片描述

參考: