日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux多线程实践(4) --线程特定数据

發(fā)布時間:2025/3/17 linux 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux多线程实践(4) --线程特定数据 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

線程特定數(shù)據(jù)

int pthread_key_create(pthread_key_t *key, void (*destr_function) (void *)); int pthread_key_delete(pthread_key_t key);int pthread_setspecific(pthread_key_t key, const void *pointer); void * pthread_getspecific(pthread_key_t key);pthread_once_t once_control = PTHREAD_ONCE_INIT; int pthread_once(pthread_once_t *once_control, void (*init_routine) (void));

? ?在單線程程序中,我們經(jīng)常要用到"全局變量"以實現(xiàn)多個函數(shù)間共享數(shù)據(jù),?然而在多線程環(huán)境下,由于數(shù)據(jù)空間是共享的,因此全局變量也為所有線程所共有。但有時應用程序設計中有必要提供線程私有的全局變量,僅在某個線程中有效,但卻可以跨多個函數(shù)訪問。POSIX線程庫通過維護一定的數(shù)據(jù)結構來解決這個問題,這個些數(shù)據(jù)稱為(Thread-specific-data或?TSD),?線程特定數(shù)據(jù)如下圖所示:

?

?

? ?從上圖可知:當調(diào)用pthread_key_create?后會產(chǎn)生一個所有線程都可見的線程特定數(shù)據(jù)(TSD)的鍵值(如上圖中所有的線程都會得到一個pkey[1]的值),?但是這個鍵所指向的真實數(shù)據(jù)卻是不同的,雖然都是pkey[1],?但是他們并不是指向同一塊內(nèi)存,而是指向了只屬于自己的實際數(shù)據(jù),?因此,?如果線程0更改了pkey[1]所指向的數(shù)據(jù),?而并不能夠影像到線程n;

? ?在線程調(diào)用pthread_setspecific后會將每個線程的特定數(shù)據(jù)與thread_key_t綁定起來,雖然只有一個pthread_key_t,但每個線程的特定數(shù)據(jù)是獨立的內(nèi)存空間,當線程退出時會執(zhí)行destructor?函數(shù)。

/** 示例1: 設置/獲取線程特定數(shù)據(jù) 在兩個線程中分別設置/獲取線程特定數(shù)據(jù), 查看兩個線程中的數(shù)據(jù)是否是一樣的(肯定是不一樣的O(∩_∩)O~) **/ pthread_key_t key; typedef struct Tsd {pthread_t tid;char *str; } tsd_t; //用來銷毀每個線程所指向的實際數(shù)據(jù) void destructor_function(void *value) {free(value);cout << "destructor ..." << endl; }void *thread_routine(void *args) {//設置線程特定數(shù)據(jù)tsd_t *value = (tsd_t *)malloc(sizeof(tsd_t));value->tid = pthread_self();value->str = (char *)args;pthread_setspecific(key, value);printf("%s setspecific, address: %p\n", (char *)args, value);//獲取線程特定數(shù)據(jù)value = (tsd_t *)pthread_getspecific(key);printf("tid: 0x%x, str = %s\n", (unsigned int)value->tid, value->str);sleep(2);//再次獲取線程特定數(shù)據(jù)value = (tsd_t *)pthread_getspecific(key);printf("tid: 0x%x, str = %s\n", (unsigned int)value->tid, value->str);pthread_exit(NULL); }int main() {//這樣每個線程當中都會有一個key可用了,//但是每個key所綁定的實際區(qū)域需要每個線程自己指定pthread_key_create(&key, destructor_function);pthread_t tid1, tid2;pthread_create(&tid1, NULL, thread_routine, (void *)"thread1");pthread_create(&tid2, NULL, thread_routine, (void *)"thread2");pthread_join(tid1, NULL);pthread_join(tid2, NULL);pthread_key_delete(key);return 0; } /** 示例2:運用pthread_once, 讓key只初始化一次 注意: 將對key的初始化放入到init_routine中 **/ pthread_key_t key; pthread_once_t once_control = PTHREAD_ONCE_INIT; typedef struct Tsd {pthread_t tid;char *str; } tsd_t;//線程特定數(shù)據(jù)銷毀函數(shù), //用來銷毀每個線程所指向的實際數(shù)據(jù) void destructor_function(void *value) {free(value);cout << "destructor ..." << endl; }//初始化函數(shù), 將對key的初始化放入該函數(shù)中, //可以保證inti_routine函數(shù)只運行一次 void init_routine() {pthread_key_create(&key, destructor_function);cout << "init..." << endl; }void *thread_routine(void *args) {pthread_once(&once_control, init_routine);//設置線程特定數(shù)據(jù)tsd_t *value = (tsd_t *)malloc(sizeof(tsd_t));value->tid = pthread_self();value->str = (char *)args;pthread_setspecific(key, value);printf("%s setspecific, address: %p\n", (char *)args, value);//獲取線程特定數(shù)據(jù)value = (tsd_t *)pthread_getspecific(key);printf("tid: 0x%x, str = %s\n", (unsigned int)value->tid, value->str);sleep(2);//再次獲取線程特定數(shù)據(jù)value = (tsd_t *)pthread_getspecific(key);printf("tid: 0x%x, str = %s\n", (unsigned int)value->tid, value->str);pthread_exit(NULL); }int main() {pthread_t tid1, tid2;pthread_create(&tid1, NULL, thread_routine, (void *)"thread1");pthread_create(&tid2, NULL, thread_routine, (void *)"thread2");pthread_join(tid1, NULL);pthread_join(tid2, NULL);pthread_key_delete(key);return 0; }


附-Linux/Unix線程私有數(shù)據(jù)實現(xiàn)思想:

原文連接:http://blog.csdn.net/caigen1988/article/details/7901248

? ?線程私有數(shù)據(jù)實現(xiàn)的主要思想是:在分配線程私有數(shù)據(jù)之前,創(chuàng)建與該數(shù)據(jù)相關聯(lián)的鍵,這個鍵可以被進程中的所有線程使用,但每個線程把這個鍵與不同的線程私有數(shù)據(jù)地址進行關聯(lián),需要說明的是每個系統(tǒng)支持有限數(shù)量的線程特定數(shù)據(jù)元素(如:限制為128個)。那么這個鍵的實現(xiàn)原理是什么呢?

? ? 其實系統(tǒng)為每個進程維護了一個稱之為 Key 結構的結構數(shù)組,如下圖所示:


(圖1)

? ?在上圖中Key?結構的“標志”指示這個數(shù)據(jù)元素是否正在使用。在剛開始時所有的標志初始化為“不在使用”。當一個線程調(diào)用pthread_key_create創(chuàng)建一個新的線程特定數(shù)據(jù)元素時,系統(tǒng)會搜索Key結構數(shù)組,找出第一個“不在使用”的元素。并把該元素的索引(0~127,稱為“鍵”)返回給調(diào)用線程。

? ?除了進程范圍內(nèi)的Key結構數(shù)組之外,系統(tǒng)還在進程內(nèi)維護了關于多個線程的多條信息。這些特定于線程的信息我們稱之為pthread結構。其中部分內(nèi)容是我們稱之為pkey數(shù)組的一個128個元素的指針數(shù)組。系統(tǒng)維護的關于每個線程的信息結構圖如下:

?

(圖2)

? ?在上圖中,pkey數(shù)組所有元素都被初始化為空指針。這些128個指針是和進程內(nèi)128個可能的鍵逐一關聯(lián)的值。

那么當我們調(diào)用pthread_key_create函數(shù)時,系統(tǒng)會為我們做什么呢?

????系統(tǒng)首先會返回給我們一個Key結構數(shù)組中第一個“未被使用”的鍵(即索引值),每個線程可以隨后通過該鍵找到對應的位置,并且為這個位置存儲一個值(指針)。?一般來說,這個指針通常是每個線程通過調(diào)用malloc來獲得的。

知道了大概的私有數(shù)據(jù)實現(xiàn)的原理,那么在編程中如何使用線程的特定數(shù)據(jù)呢?

? ?假設一個進程被啟動,并且多個線程被創(chuàng)建。?其中一個線程調(diào)用pthread_key_create。系統(tǒng)在Key結構數(shù)組(圖1)中找到第1個未使用的元素。并把它的索引(0~127)返回給調(diào)用者。我們假設找到的索引為1。

之后線程調(diào)用pthread_getspecific獲取本線程的pkey[1]?的值(圖(2)中鍵1所值的指針),?返回值是一個空值,線程那么調(diào)用malloc分配內(nèi)存區(qū)并初始化此內(nèi)存區(qū)。?之后線程調(diào)用pthread_setspecific把對應的所創(chuàng)建鍵的線程特定數(shù)據(jù)指針(pkey[1])?設置為指向它剛剛分配的內(nèi)存區(qū)。下圖指出了此時的情形。

?

(圖3)

明白了怎樣獲取線程的特定數(shù)據(jù)值,那么如果線程終止時系統(tǒng)會執(zhí)行什么操作呢?

? ?我們知道,一個線程調(diào)用pthread_key_create創(chuàng)建某個特定的數(shù)據(jù)元素時,所指定的參數(shù)之一便是指向析構函數(shù)的指針。當一個線程終止時,系統(tǒng)將掃描該線程的pkey數(shù)組,為每個非空的pkey指針調(diào)用相應的析構函數(shù)。?相應的析構函數(shù)是存放在圖1中的Key數(shù)組中的函數(shù)指針。這是一個線程終止時其線程特定數(shù)據(jù)的釋放手段。

總結

以上是生活随笔為你收集整理的Linux多线程实践(4) --线程特定数据的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。