Linux系統編程——線程私人資料,linux編程線程私人
在多線程程式中,經常要用全域變數來實現多個函數間的資料共用。由於資料空間是共用的,因此全域變數也為所有線程共有。
測試代碼如下:
#include <stdio.h>#include <pthread.h>#include <unistd.h>#include <stdlib.h>int key = 100; //全域變數void *helloworld_one(void *arg){printf("the message is %s\n",(char *)arg);key = 10;printf("key=%d, the child id is %lu\n", key, pthread_self());return NULL;}void *helloworld_two(void *arg){printf("the message is %s\n", (char *)arg);sleep(1);printf("key=%d, the child id is %lu\n", key, pthread_self());return NULL;}int main(int argc, char *argv[]){pthread_t thread_id_one;pthread_t thread_id_two;//建立線程pthread_create(&thread_id_one, NULL, helloworld_one, "helloworld_one");pthread_create(&thread_id_two, NULL, helloworld_two, "helloworld_two");//等待線程結束,回收資源pthread_join(thread_id_one, NULL);pthread_join(thread_id_two, NULL);return 0;}
運行結果如下:
由運行結果可以看出,其中一個線程對全域變數的修改將影響到另一個線程的訪問。
但有時應用程式設計中必要提供線程私人的全域變數,這個變數僅線上程中有效,但卻可以跨過多個函數訪問。比如在程式裡可能需要每個線程維護一個鏈表,而會使用相同的函數來操作這個鏈表,最簡單的方法就是使用同名而不同變數地址的線程相關資料結構。這樣的資料結構可以由 Posix 線程庫維護,成為線程私人資料 (Thread-specific Data,或稱為 TSD)。
下面介面所需標頭檔:
#include <pthread.h>
1)建立線程私人資料
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
功能:
建立一個類型為 pthread_key_t 類型的私人資料變數( key )。
參數:
key:在分配( malloc )線程私人資料之前,需要建立和線程私人資料相關聯的鍵( key ),這個鍵的功能是獲得對線程私人資料的訪問權。
destructor:清理函數名字( 如:fun )。當線程退出時,如果線程私人資料地址不是非 NULL,此函數會自動被調用。該函數指標可以設成 NULL ,這樣系統將調用預設的清理函數。
回呼函數其定義如下:
void fun(void *arg)
{
// arg 為 key 值
}
返回值:
成功:0
失敗:非 0
不論哪個線程調用 pthread_key_create(),所建立的 key 都是所有線程可訪問,但各個線程可根據自己的需要往 key 中填入不同的值,相當於提供了一個同名不同值的變數。
2)登出線程私人資料
int pthread_key_delete(pthread_key_t key);
功能:
登出線程私人資料。這個函數並不會檢查當前是否有線程正使用線程私人資料( key ),也不會調用清理函數 destructor() ,而只是將線程私人資料( key )釋放以供下一次調用 pthread_key_create() 使用。
參數:
key:待登出的私人資料。
返回值:
成功:0
失敗:非 0
3)設定線程私人資料的關聯
int pthread_setspecific(pthread_key_t key, const void *value);
功能:
設定線程私人資料( key ) 和 value 關聯,注意,是 value 的值(不是所指的內容)和 key 相關聯。
參數:
key:線程私人資料。
value:和 key 相關聯的指標。
返回值:
成功:0
失敗:非 0
4)讀取線程私人資料所關聯的值
void *pthread_getspecific(pthread_key_t key);
功能:
讀取線程私人資料( key )所關聯的值。
參數:
key:線程私人資料。
返回值:
成功:線程私人資料( key )所關聯的值。
失敗:NULL
範例程式碼如下:
// this is the test code for pthread_key #include <stdio.h> #include <pthread.h> pthread_key_t key;// 私人資料,全域變數void echomsg(void *t) { printf("[destructor] thread_id = %lu, param = %p\n", pthread_self(), t); } void *child1(void *arg) { int i = 10;pthread_t tid = pthread_self(); //線程號printf("\nset key value %d in thread %lu\n", i, tid); pthread_setspecific(key, &i); // 設定私人資料printf("thread one sleep 2 until thread two finish\n\n");sleep(2); printf("\nthread %lu returns %d, add is %p\n",tid, *((int *)pthread_getspecific(key)), pthread_getspecific(key) ); } void *child2(void *arg) { int temp = 20;pthread_t tid = pthread_self(); //線程號printf("\nset key value %d in thread %lu\n", temp, tid); pthread_setspecific(key, &temp); //設定私人資料sleep(1); printf("thread %lu returns %d, add is %p\n", tid, *((int *)pthread_getspecific(key)), pthread_getspecific(key)); } int main(void) { pthread_t tid1,tid2; pthread_key_create(&key, echomsg); // 建立pthread_create(&tid1, NULL, child1, NULL); pthread_create(&tid2, NULL, child2, NULL); pthread_join(tid1, NULL);pthread_join(tid2, NULL);pthread_key_delete(key); // 登出return 0; }
運行結果如下:
從運行結果來看,各線程對自己的私人資料操作互不影響。也就是說,雖然 key 是同名且全域,但訪問的記憶體空間並不是同一個。
本教程範例程式碼下載請點此處。
本文