线程的私有数据
一. 概念及作用?
在單線程程序中,我們經常要用到"全局變量"以實現多個函數間共享數據。在多線程環境下,由于數據空間是共享的,因此全局變量也為所有線程所共有?,F在有一全局變量,所有線程都可以使用它,改變它的值。而如果每個線程希望能單獨擁有它,那么就需要使用線程存儲了。表面上看起來這是一個全局變量,所有線程都可以使用它,而它的值在每一個線程中又是單獨存儲的。這就是線程存儲的意義。這樣的數據結構可以由Posix線程庫維護,稱為線程私有數據(Thread-specific Data,或TSD)。
具體用法如下:
1.創建一個類型為pthread_key_t類型的變量。
2.調用pthread_key_create()來創建該變量。該函數有兩個參數,第一個參數就是上面聲明的pthread_key_t變量,第二個參數是一個清理函數,用來在線程釋放該線程存儲的時候被調用。該函數指針可以設成NULL,這樣系統將調用默認的清理函數。
3.當線程中需要存儲特殊值的時候,可以調用pthread_setspcific()。該函數有兩個參數,第一個為前面聲明的pthread_key_t變量,第二個為void*變量,這樣你可以存儲任何類型的值。
4.如果需要取出所存儲的值,調用pthread_getspecific()。該函數的參數為前面提到的pthread_key_t變量,該函數返回void *類型的值。
二. 創建和注銷?
Posix定義了兩個API分別用來創建和注銷TSD:?
int pthread_key_create(pthread_key_t *key, void (*destr_function) (void *));
該函數從TSD池中分配一項,將其值賦給key供以后訪問使用。如果destr_function不為空,在線程退出(pthread_exit())時將以key所關聯的數據為參數調用destr_function(),以釋放分配的緩沖區。
不論哪個線程調用pthread_key_create(),所創建的key都是所有線程可訪問的,但各個線程可根據自己的需要往key中填入不同的值,這就相當于提供了一個同名而不同值的全局變量。在LinuxThreads的實現中,TSD池用一個結構數組表示:
static struct pthread_key_struct pthread_keys[PTHREAD_KEYS_MAX] = { { 0, NULL } };
創建一個TSD就相當于將結構數組中的某一項設置為"in_use",并將其索引返回給*key,然后設置destructor函數為destr_function。?
注銷一個TSD采用如下API:?
int pthread_key_delete(pthread_key_t key);
這個函數并不檢查當前是否有線程正使用該TSD,也不會調用清理函數(destr_function),而只是將TSD釋放以供下一次調用pthread_key_create()使用。在LinuxThreads中,它還會將與之相關的線程數據項設為NULL(見"訪問")。
三. 訪問?
TSD的讀寫都通過專門的Posix Thread函數進行,其API定義如下:?
int pthread_setspecific(pthread_key_t key, const void *pointer);?
void * pthread_getspecific(pthread_key_t key) ;
寫入(pthread_setspecific())時,將pointer的值(不是所指的內容)與key相關聯,而相應的讀出函數則將與key相關聯的數據讀出來。數據類型都設為void *,因此可以指向任何類型的數據。
在LinuxThreads中,使用了一個位于線程描述結構(_pthread_descr_struct)中的二維void *指針數組來存放與key關聯的數據,數組大小由以下幾個宏來說明:
?#define PTHREAD_KEY_2NDLEVEL_SIZE 32?
#define PTHREAD_KEY_1STLEVEL_SIZE \?
((PTHREAD_KEYS_MAX + PTHREAD_KEY_2NDLEVEL_SIZE - 1)?
/ PTHREAD_KEY_2NDLEVEL_SIZE)?
其中在/usr/include/bits/local_lim.h中定義了PTHREAD_KEYS_MAX為1024,因此一維數組大小為32。而具體存放的位置由key值經過以下計算得到:
idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE?
idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE?
也就是說,數據存放與一個32×32的稀疏矩陣中。同樣,訪問的時候也由key值經過類似計算得到數據所在位置索引,再取出其中內容返回。?
四. 使用范例?
以下這個例子說明如何使用這一機制達到存儲線程私有數據的目的。?
運行結果如下:
hello
thread 1082350784 enter
thread 1090739264 enter
thread 1090739264 returns 1090739264
thread 1082350784 returns 1082350784
main thread exit
轉載于:https://www.cnblogs.com/Zoran-/p/5819278.html
總結