在多線程環境下,進程內的所有線程共享進程的數據空間,因此全局變量為所有線程共有。在程序設計中有時需要保存線程自己的全局變量,這種特殊的變量僅在某個線程內部有效。如常見的變量errno,它返回標準的出錯代碼。errno不應該是一個局部變量,幾乎每個函數都應該可以訪問它;但它又不能作為一個全局變量,否則在一個線程里輸出的很可能是另一個線程的出錯信息,這個問題可以通過創建線程的私有數據(Thread-specific Data,或TSD)來解決。在線程內部,線程私有數據可以被各個函數訪問,但它對其他線程是屏蔽的。
線程私有數據采用了一種被稱為一鍵多值的技術,即一個鍵對應多個數值。訪問數據時都是通過鍵值來訪問,好像是對一個變量進行訪問,其實是在訪問不同的數據。使用線程私有數據時,首先要為每個線程數據創建一個相關聯的鍵。在各個線程內部,都使用這個公用的鍵來指代線程數據,但是在不同的線程中,這個鍵代表的數據是不同的。操作線程私有數據的函數主要有4個:pthread_key_create(創建一個鍵),pthread_setspecific(為一個鍵設置線程私有數據),pthread_getspecific(從一個鍵讀取線程私有數據),pthread_key_delete(刪除一個鍵)。這幾個函數的聲明如下:
#include <pthread.h>
int pthread_key_create(pthread_key_t *key,void (*destr_function)(void *));
int pthread_setspecific(pthread_key_t key,const void *pointer));
void *pthread_getspecific(pthread_key_t key);
int pthread_key_delete(pthread_key_t key);
pthread_key_create:從Linux的TSD池中分配一項,將其值賦給key供以后訪問使用,它的第一個參數key為指向鍵值的指針,第二個參數為一個函數指針,如果指針不為空,則在線程退出時將以key所關聯的數據為參數調用destr_function(),釋放分配的緩沖區。
key一旦被創建,所有線程都可以訪問它,但各線程可以根據自己的需要往key中填入不同的值,這就相當于提供了一個同名而不同值的全局變量,一鍵多值。一鍵多值靠的是一個關鍵數據結構數組,即TSD池其結構如下:
static struct pthread_key_struct pthread_keys[PTHREAD_KEYS_MAX] ={{0,NULL}};
創建一個TSD就相當于將結構數組中的某一項設置為“in_use”,并將其索引返回給*key,然后設置destructor函數destr_function。
pthread_setspecific:該函數將pointer的值(不是內容)與key相關聯。用pthread_setspecific為一個鍵指定新的線程數據時,線程必須先釋放原有的線程數據用以回收空間。
pthread_getspecific:通過該函數得到與key相關聯的數據。
pthread_key_delete:該函數用來刪除一個鍵,鍵所占用的內存將被釋放。需要注意的是,鍵占用的內存被釋放,與該鍵關聯的線程數據所占用的內存并不被釋放。因此,線程數據的釋放必須在釋放鍵之前完成。
例8-4將實現如何創建和使用線程的私有數據,具體代碼如下所示。
例8-4
#include <stdio.h>
#include <string.h>
#include <pthread.h>
pthread_key_t key;
void * thread2(void *arg)
{
int tsd = 5;
printf("thread %d is running\n",pthread_self());
pthread_setspecific(key,(void *)tsd);
printf("thread %d returns %d\n",pthread_self(),pthread_getspecific(key));
}
void * thread1(void *arg)
{
int tsd = 0;
pthread_t thid2;
printf("thread %d is running\n",pthread_self());
pthread_setspecific(key,(void *)tsd);
pthread_create(&thid2,NULL,thread2,NULL);
sleep(2);
printf("thread %d return %d\n",pthread_self(),pthread_getspecific(key));
}
int main(void)
{
pthread_t thid1;
printf("main thread begins running\n");
pthread_key_create(&key,NULL);
pthread_create(&thid1,NULL,thread1,NULL);
sleep(5);
pthread_key_delete(key);
printf("main thread exit\n");
return 0;
}
編譯并執行,結果如下:
$ gcc -o 8-4 8-4.c -g -l pthread
$ ./8-4
main thread begins running
thread -1209746544 is running
thread -1218139248 is running
thread -1218139248 returns 5
thread -1209746544 return 0
main thread exit
程序說明:程序中,主線程創建了線程thread1,線程thread1創建了線程thread2。兩個線程分別將tsd作為線程私有數據。從程序運行結果可以看出,兩個線程tsd的修改互不干擾,可以看出thread2先于thread1結束,線程在創建thread2后,睡眠3s等待thread2執行完畢。主線程睡眠5s等待thread1結束。可以看出thread2對tsd的修改并沒影響到thread1的tsd的取值。
posted on 2010-05-29 15:16
何克勤 閱讀(2409)
評論(0) 編輯 收藏 所屬分類:
GNU Linux/Unix 、
Linux 多線程