Pthread - 線程特定數據(thread-specified data)
在 Pthread 中,線程特定數據(thread-specified data,以下簡稱 TSD)是綁定由pthread_key_create()函數創建的 key 的屬於調用線程自身的數據。簡單地說就是一個全局變量可以被多個線程訪問,但是在每個線程中該全局變量指向由本線程設定的值,而且每個線程都可以通過該全局變量訪問到本線程設定的值,彼此互不干擾。以下是操作 TSD 的函數:
void *pthread_getspecific(pthread_key_t key); int pthread_setspecific(pthread_key_t key, const void *value); int pthread_key_create(pthread_key_t *key, void (*destructor)(void *)); int pthread_key_delete(pthread_key_t key);
以下爲測試程序:
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUM_THREADS 2
#define ERROR(func, no) { \
fprintf(stderr, "%s: %s\n", func, strerror(no)); \
exit(EXIT_FAILURE); \
}
pthread_key_t key_tsd;
typedef struct tsd {
pthread_t tid; // thread ID
char *str; //
} tsd_t;
pthread_once_t once_control = PTHREAD_ONCE_INIT;
void destory_routine(void* value) {
printf("destory ...\n");
free(value); //delete dynamic storage allocated to each TSD
}
void init_routine() {
int ret;
ret = pthread_key_create(&key_tsd, destory_routine);
if(ret) {
ERROR("pthread_key_create", ret);
}
printf("Thread-specified data key initialized\n");
}
void* thread_routine(void *arg) {
//key will be initialized twice
//pthread_once_t once_control = PTHREAD_ONCE_INIT;
pthread_once(&once_control, init_routine); // make sure initialization actually only run once
pthread_t tid = pthread_self();
tsd_t* val = (tsd_t*)malloc(sizeof(tsd_t));
val->tid = tid;
val->str = (char*)arg;
pthread_setspecific(key_tsd, val);
printf("Thread %#lx set thread-specific data: %p\n",
(size_t)tid, val);
val = pthread_getspecific(key_tsd);
printf("Thread %#lx get thread-specific data: %s\n",
(size_t)val->tid, val->str);
sleep(2);
val = pthread_getspecific(key_tsd);
printf("Thread %#lx get thread-specific data: %s\n",
(size_t)val->tid, val->str);
pthread_exit(NULL);
}
int main(int argc, char** argv)
{
int ret, i;
pthread_t tid[NUM_THREADS];
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
if((ret=pthread_create(&tid[0], &attr, thread_routine, "Thread 1"))){
ERROR("pthread_create", ret);
}
if((ret=pthread_create(&tid[1], &attr, thread_routine, "Thread 2"))){
ERROR("pthread_create", ret);
}
pthread_attr_destroy(&attr);
for(i=0; i<NUM_THREADS; ++i) {
ret = pthread_join(tid[i], NULL);
if(ret) {
ERROR("pthread_join", ret);
}
}
pthread_key_delete(key_tsd);
exit(EXIT_SUCCESS);
}
運行效果:
從程序的運行結果可以看出:兩線程通過相同的可以訪問到本線程的特定數據,並且程序中特意 sleep 一段時間後再次訪問 TSD 結果不變,進一步驗證 TSD 的特性。值得注意的是上述程序中調用了 pthread_once 函數來創建 pthread_key_t
變量,程序的運行結果可以發現該 key 只被初始化了一次,這是通過設置 pthread_once 函數的 once_control 參數實現的,而且要注意該參數的生存週期應爲整個程序的運行週期,也就是說該參數應是一個全局變量或靜態局部變量。而 destroy_routine 調用了兩次,釋放了各自線程爲 TSD分配的動態內存。
once_control爲局部變量, key被初始化兩次: