在單線程程式中,我們經常要用到"全局變量"以實作多個函數間共享資料, 然而在多線程環境下,由于資料空間是共享的,是以全局變量也為所有線程所共有。但有時應用程式設計中有必要提供線程私有的全局變量,僅在某個線程中有效,但卻可以跨多個函數通路。POSIX線程庫通過維護一定的資料結構來解決這個問題,這個些資料稱為(Thread-specific-data或 TSD), 線程特定資料如下圖所示:

從上圖可知:當調用pthread_key_create 後會産生一個所有線程都可見的線程特定資料(TSD)的鍵值(如上圖中所有的線程都會得到一個pkey[1]的值), 但是這個鍵所指向的真實資料卻是不同的,雖然都是pkey[1], 但是他們并不是指向同一塊記憶體,而是指向了隻屬于自己的實際資料, 是以, 如果線程0更改了pkey[1]所指向的資料, 而并不能夠影像到線程n;
線上程調用pthread_setspecific後會将每個線程的特定資料與thread_key_t綁定起來,雖然隻有一個pthread_key_t,但每個線程的特定資料是獨立的記憶體空間,當線程退出時會執行destructor 函數。
附-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數組中的函數指針。這是一個線程終止時其線程特定資料的釋放手段。