進程內的所有線程共享進程的數據空間,所以全局變量為所有線程共有。在某些場景下,線程需要保存自己的私有數據,這時可以創建線程私有數據(Thread-specific Data)TSD來解決。在線程內部,私有數據可以被線程的各個接口訪問,但對其他線程屏蔽。
線程私有數據采用了一鍵多值技術,及一個key對應多個值。訪問數據都是通過鍵值來訪問的。
使用線程私有數據時,需要對每個線程創建一個關聯 的key,linux中主要有四個接口來實現:
1、pthread_key_create:創建一個鍵
int pthread_key_create(pthread_key_t *key, void (*destr_function) (void*));
首先從linux的TSD池中分配一項,然后將其值賦給key供以后訪問使用。接口的第一個參數是指向參數的指針,第二參數是函數指針,如果該指針不為空,那么在線程執行完畢退出時,已key指向的內容為入參調用destr_function(),釋放分配的緩沖區以及其他數據。
key被創建之后,因為是全局變量,所以所有的線程都可以訪問。各個線程可以根據需求往key中,填入不同的值,這就相當於提供了一個同名而值不同的全局變量,即一鍵多值。一鍵多值依靠的一個結構體數組,即
static struct pthread_key_struct pthread_keys[PTHREAD_KEYS_MAX] ={{0,NULL}};
pthread_key_struct 的定義為:
struct pthread_key_struct { /* Sequence numbers. Even numbers indicated vacant entries. Note that zero is even. We use uintptr_t to not require padding on 32- and 64-bit machines. On 64-bit machines it helps to avoid wrapping, too. */ uintptr_t seq; /* Destructor for the data. */ void (*destr) (void *); };
PTHREAD_KEYS_MAX值為1024
創建一個TSD,相當於將結構體數組的某一個元素的seq值設置為為“in_use”,並將其索引返回給*key,然后設置destr_function()為destr()。pthread_key_create創建一個新的線程私有數據key時,系統會搜索其所在進程的key結構數組,找出一個未使用的元素,將其索引賦給*key。
2、pthread_setspecific:為指定鍵值設置線程私有數據
int pthread_setspecific(pthread_key_t key, const void *pointer);
該接口將指針pointer的值(指針值而非其指向的內容)與key相關聯,用pthread_setspecific為一個鍵指定新的線程數據時,線程必須釋放原有的數據用以回收空間。
3、pthread_getspecific:從指定鍵讀取線程的私有數據
void * pthread_getspecific(pthread_key_t key);
4、pthread_key_delete:刪除一個鍵
void * pthread_getspecific(pthread_key_t key);
該接口用於刪除一個鍵,功能僅僅是將該key在結構體數組pthread_keys對應的元素設置為“un_use”,與改key相關聯的線程數據是不會被釋放的,因此線程私有數據的釋放必須在鍵刪除之前。