Linux多執行緒實踐 4 執行緒特定資料

2021-09-21 16:39:07 字數 3287 閱讀 4823

int pthread_key_create(pthread_key_t *key, void (*destr_function) (void *));

int pthread_key_delete(pthread_key_t key);

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

void * pthread_getspecific(pthread_key_t key);

pthread_once_t once_control = pthread_once_init;

int pthread_once(pthread_once_t *once_control, void (*init_routine) (void));

在單執行緒程式中,我們經常要用到"全域性變數"以實現多個函式間共享資料, 然而在多執行緒環境下,由於資料空間是共享的,因此全域性變數也為所有執行緒所共有。但有時應用程式設計中有必要提供執行緒私有的全域性變數,僅在某個執行緒中有效,但卻可以跨多個函式訪問。posix執行緒庫通過維護一定的資料結構來解決這個問題,這個些資料稱為(thread-specific-data或 tsd), 執行緒特定資料如下圖所示:

從上圖可知:當呼叫pthread_key_create 後會產生乙個所有執行緒都可見的執行緒特定資料(tsd)的鍵值(如上圖中所有的執行緒都會得到乙個pkey[1]的值), 但是這個鍵所指向的真實資料卻是不同的,雖然都是pkey[1], 但是他們並不是指向同一塊記憶體,而是指向了只屬於自己的實際資料, 因此, 如果執行緒0更改了pkey[1]所指向的資料, 而並不能夠影像到執行緒n;

/** 示例1: 設定/獲取執行緒特定資料

在兩個執行緒中分別設定/獲取執行緒特定資料, 檢視兩個執行緒中的資料是否是一樣的(肯定是不一樣的o(∩_∩)o~)

**/pthread_key_t key;

typedef struct tsd

tsd_t;

//用來銷毀每個執行緒所指向的實際資料

void destructor_function(void *value)

void *thread_routine(void *args)

int main()

/** 示例2:運用pthread_once, 讓key只初始化一次

注意: 將對key的初始化放入到init_routine中

**/pthread_key_t key;

pthread_once_t once_control = pthread_once_init;

typedef struct tsd

tsd_t;

//執行緒特定資料銷毀函式,

//用來銷毀每個執行緒所指向的實際資料

void destructor_function(void *value)

//初始化函式, 將對key的初始化放入該函式中,

//可以保證inti_routine函式只執行一次

附-linux/unix執行緒私有資料實現思想:

原文連線:

執行緒私有資料實現的主要思想是:在分配執行緒私有資料之前,建立與該資料相關聯的鍵,這個鍵可以被程序中的所有執行緒使用,但每個執行緒把這個鍵與不同的執行緒私有資料位址進行關聯,需要說明的是每個系統支援有限數量的執行緒特定資料元素(如:限制為128個)。那麼這個鍵的實現原理是什麼呢?

其實系統為每個程序維護了乙個稱之為

key結構的結構陣列,如下圖所示:

(圖1)

在上圖中key 結構的「標誌」指示這個資料元素是否正在使用。在剛開始時所有的標誌初始化為「不在使用」。當乙個執行緒呼叫pthread_key_create建立乙個新的執行緒特定資料元素時,系統會搜尋key結構陣列,找出第乙個「不在使用」的元素。並把該元素的索引(0~127,稱為「鍵」)返回給呼叫執行緒。

除了程序範圍內的key結構陣列之外,系統還在程序內維護了關於多個執行緒的多條資訊。這些特定於執行緒的資訊我們稱之為pthread結構。其中部分內容是我們稱之為pkey陣列的乙個128個元素的指標陣列。系統維護的關於每個執行緒的資訊結構圖如下:

(圖2)

在上圖中,pkey陣列所有元素都被初始化為空指標。這些128個指標是和程序內128個可能的鍵逐一關聯的值。

那麼當我們呼叫pthread_key_create函式時,系統會為我們做什麼呢?

系統首先會返回給我們乙個key結構陣列中第乙個「未被使用」的鍵(即索引值),每個執行緒可以隨後通過該鍵找到對應的位置,並且為這個位置儲存乙個值(指標)。 一般來說,這個指標通常是每個執行緒通過呼叫malloc來獲得的。

知道了大概的私有資料實現的原理,那麼在程式設計中如何使用執行緒的特定資料呢?

假設乙個程序被啟動,並且多個執行緒被建立。 其中乙個執行緒呼叫pthread_key_create。系統在key結構陣列(圖1)中找到第1個未使用的元素。並把它的索引(0~127)返回給呼叫者。我們假設找到的索引為1。

之後執行緒呼叫pthread_getspecific獲取本執行緒的pkey[1] 的值(圖(2)中鍵1所值的指標), 返回值是乙個空值,執行緒那麼呼叫malloc分配記憶體區並初始化此記憶體區。 之後執行緒呼叫pthread_setspecific把對應的所建立鍵的執行緒特定資料指標(pkey[1]) 設定為指向它剛剛分配的記憶體區。下圖指出了此時的情形。

(圖3)

明白了怎樣獲取執行緒的特定資料值,那麼如果執行緒終止時系統會執行什麼操作呢?

我們知道,乙個執行緒呼叫pthread_key_create建立某個特定的資料元素時,所指定的引數之一便是指向析構函式的指標。當乙個執行緒終止時,系統將掃瞄該執行緒的pkey陣列,為每個非空的pkey指標呼叫相應的析構函式。 相應的析構函式是存放在圖1中的key陣列中的函式指標。這是乙個執行緒終止時其執行緒特定資料的釋放手段。

Linux多執行緒實踐(四 )執行緒的特定資料

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

Linux多執行緒實踐 7 多執行緒排序對比

int pthread barrier init pthread barrier t restrict barrier,const pthread barrierattr t restrict attr,unsigned count int pthread barrier destroy pthre...

Linux多執行緒實踐 7 多執行緒排序對比

int pthread barrier init pthread barrier t restrict barrier,const pthread barrierattr t restrict attr,unsigned count int pthread barrier destroy pthre...