執行緒特定資料

2021-09-02 21:19:11 字數 2623 閱讀 2263

執行緒特定資料也稱執行緒私有資料,是儲存和查詢某個特定執行緒相關資料的一種機制。在分配執行緒特定資料之前,需要建立與該資料相關聯的鍵,以用於獲取對執行緒特定資料的訪問。使用函式 pthread_key_create 可建立乙個鍵,而對所有的執行緒,都可以通過 pthread_key_delete 來取消鍵與執行緒特定資料值之間的關聯關係。

#include

int pthread_key_create(pthread_key_t *keyp, void (*destructor)(void *));

int pthread_key_delete(pthread_key_t key);

/* 兩個函式返回值:若成功,返回 0;否則,返回錯誤編號 */

建立的鍵儲存在 keyp 指向的記憶體單元中,這個鍵可以被程序中的所有執行緒使用,但每個執行緒把這個鍵與不同的執行緒特定資料位址進行關聯。建立新鍵時,每個執行緒的資料位址都設為空值。除了建立鍵以外,pthread_key_create 還可以為該鍵關聯乙個可選擇的析構函式。當這個執行緒退出時,如果資料位址已經被置為非空值,那麼析構函式就會被呼叫,它唯一的引數就是該資料位址。當執行緒呼叫 pthread_exit 或者返回時,析構函式就會被呼叫;而當執行緒取消時,只有在最後的清理處理程式返回後,析構函式才會被呼叫。執行緒通常使用 malloc 為執行緒特定資料分配記憶體,所以析構函式經常呼叫 free 函式來釋放已分配的記憶體,以免產生記憶體洩露。執行緒可以為執行緒特定資料分配多個鍵,每個鍵都可以關聯乙個析構函式。執行緒退出時,執行緒特定資料的析構函式將按照作業系統實現中定義的順序被呼叫。當所有的析構函式都呼叫完成後,系統會檢查是否還有非空的執行緒特定資料值與鍵關聯。如果有的話,會再次呼叫析構函式。該過程會一直重複直到執行緒所有的鍵都為空執行緒特定資料值,或者已經做了 pthread_destructor_iterations 次嘗試。

呼叫 pthread_key_delete 並不會啟用與鍵關聯的析構函式,要釋放任何與鍵關聯的執行緒特定資料值的記憶體,需要在應用程式中採取額外的步驟。

為確保分配的鍵不會因初始化階段的競爭而發生變動,可以使用函式 pthread_once。鍵一旦建立以後,就可以通過 pthread_setspecific 函式把鍵和執行緒特定資料關聯起來,也可通過 pthread_getspecific 函式獲得執行緒特定資料的位址。

#include

pthread_once_t initflag = pthread_once_init;

int pthread_once(pthread_once_t *initflag, void (*initfn)(void));

int pthread_setspecific(pthread_key_t key, const void *value);

/* 兩個函式返回值:若成功,返回 0;否則,返回錯誤編號 */

void *pthread_getspecific(pthread_key_t key);

/* 返回值:執行緒特定資料值;若沒有值與該鍵關聯,返回 null */

這裡的 initflag 必須是乙個非本地變數(如全域性變數或靜態變數),而且必須初始化為 pthread_once_init。就算每個執行緒都呼叫 pthread_once,系統也能保證初始化例程 initfn 只被呼叫一次,這可以避免建立鍵時出現衝突。

下面給出了 getenv 的乙個假設實現,它使用執行緒特定資料來維護每個執行緒的資料緩衝區副本,用於存放各自的返回字串。

#include

#include

#include

static pthread_key_t key;

static pthread_once_t init_done = pthread_once_init;

static pthread_mutex_t env_mutex = pthread_mutex_initializer;

static void key_init(void)

#define maxstringsz 4096

extern char **environ;

char *getenv(const char *name)

pthread_setspecific(key, env_buf);

}int i = 0, len = strlen(name);

for(; environ[i] != null; i++)

}pthread_mutex_unlock(&env_mutex);

return null;

}

這裡使用 pthread_once 來確保只為將要使用的執行緒特定資料建立乙個鍵。如果 pthread_getspecific 返回的是空指標,就需要先分配記憶體緩衝區,然後再把鍵與該記憶體緩衝區關聯起來,否則就使用返回的記憶體緩衝區。對析構函式,使用 free 來釋放之前由 malloc 分配的記憶體。只有當執行緒特定資料值為非空時,析構函式才會被呼叫。

注意,相較於[url=執行緒重入[/url]中實現的 getenv_r 版本,雖然該版本的 genenv 也使用了互斥量來保證執行緒安全,但它並不是非同步訊號安全的。對訊號處理程式而言,即使使用遞迴的互斥量,該版本也不可能是可重入的,因為它呼叫了本身就不是非同步訊號安全的 malloc 函式。

Linux執行緒 執行緒特定資料

在單執行緒程式中。我們常常要用到 全域性變數 以實現多個函式間共享資料,然而在多執行緒環境下。因為資料空間是共享的。因此全域性變數也為全部執行緒所共同擁有。但有時應用程式設計中有必要提供執行緒私有的全域性變數,僅在某個執行緒中有效,但卻能夠跨多個函式訪問。posix執行緒庫通過維護一定的資料結構來解...

執行緒特定資料(學習)

1 首先,為什麼要使用執行緒特定資料呢?什麼是執行緒特定資料。這牽涉到重入函式和不可重入函式。重入函式就是在多個程序或者執行緒中,可以同時進行執行的函式,可重入函式就是不可以同時執行的函式,這個主要是可能多個程序或執行緒共享了乙個變數,這個變數只有乙個,這樣同時執行的時候,就會出問題了,因為我們不知...

執行緒特定資料(筆記)

執行緒特定資料,也稱為執行緒私有資料,是儲存和查詢某個特定資料相關資料的一種機制。在單執行緒程式中,我們經常要用到 全域性變數 以實現多個函式間共享資料。在多執行緒環境下,由於資料空間是共享的,因此全域性變數也為所有所有執行緒所共有。但有時應用程式設計中有必要提供執行緒私有的全域性變數,僅在某個執行...