線程式控制制-私人資料 轉自monalisa’s_blog

來源:互聯網
上載者:User

      在多線程環境下,進程內的所有線程共用進程的資料空間,因此全域變數為所有線程共有。在程式設計中有時需要儲存線程自己的全域變數,這種特殊的變數僅在某個線程內部有效。如常見的變數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的取值。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.