線程控制--私有數據

   在多線程環境下,進程內的所有線程共享進程的數據空間,因此全局變量爲所有線程共有。在程序設計中有時需要保存線程自己的全局變量,這種特殊的變量僅在某個線程內部有效。如常見的變量errno,它返回標準的出錯代碼。errno不應該是一個局部變量,幾乎每個函數都應該可以訪問它;但它又不能作爲一個全局變量,否則在一個線程裏輸出的很可能是另一個線程的出錯信息,這個問題可以通過創建線程的私有數據(Thread-specific Data,或TSD)來解決。在線程內部,線程私有數據可以被各個函數訪問,但它對其他線程是屏蔽的。

   線程私有數據採用了一種被稱爲一鍵多值的技術,即一個鍵對應多個數值。訪問數據時都是通過鍵值來訪問,好像是對一個變量進行訪問,其實是在訪問不同的數據。使用線程私有數據時,首先要爲每個線程數據創建一個相關聯的鍵。在各個線程內部,都使用這個公用的鍵來指代線程數據,但是在不同的線程中,這個鍵代表的數據是不同的。

   操作線程私有數據的函數主要有4個:

   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將實現如何創建和使用線程的私有數據,具體代碼如下所示。
#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的取值。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章