Pthread - 線程特定數據(thread-specified data)

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被初始化兩次:
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章