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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

线程的私有数据

發布時間:2025/4/16 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 线程的私有数据 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一. 概念及作用?
在單線程程序中,我們經常要用到"全局變量"以實現多個函數間共享數據。在多線程環境下,由于數據空間是共享的,因此全局變量也為所有線程所共有?,F在有一全局變量,所有線程都可以使用它,改變它的值。而如果每個線程希望能單獨擁有它,那么就需要使用線程存儲了。表面上看起來這是一個全局變量,所有線程都可以使用它,而它的值在每一個線程中又是單獨存儲的。這就是線程存儲的意義。這樣的數據結構可以由Posix線程庫維護,稱為線程私有數據(Thread-specific Data,或TSD)。
具體用法如下:

1.創建一個類型為pthread_key_t類型的變量。

2.調用pthread_key_create()來創建該變量。該函數有兩個參數,第一個參數就是上面聲明的pthread_key_t變量,第二個參數是一個清理函數,用來在線程釋放該線程存儲的時候被調用。該函數指針可以設成NULL,這樣系統將調用默認的清理函數。

3.當線程中需要存儲特殊值的時候,可以調用pthread_setspcific()。該函數有兩個參數,第一個為前面聲明的pthread_key_t變量,第二個為void*變量,這樣你可以存儲任何類型的值。

4.如果需要取出所存儲的值,調用pthread_getspecific()。該函數的參數為前面提到的pthread_key_t變量,該函數返回void *類型的值。


二. 創建和注銷?
Posix定義了兩個API分別用來創建和注銷TSD:?

int pthread_key_create(pthread_key_t *key, void (*destr_function) (void *));

該函數從TSD池中分配一項,將其值賦給key供以后訪問使用。如果destr_function不為空,在線程退出(pthread_exit())時將以key所關聯的數據為參數調用destr_function(),以釋放分配的緩沖區。

不論哪個線程調用pthread_key_create(),所創建的key都是所有線程可訪問的,但各個線程可根據自己的需要往key中填入不同的值,這就相當于提供了一個同名而不同值的全局變量。在LinuxThreads的實現中,TSD池用一個結構數組表示:

static struct pthread_key_struct pthread_keys[PTHREAD_KEYS_MAX] = { { 0, NULL } };

創建一個TSD就相當于將結構數組中的某一項設置為"in_use",并將其索引返回給*key,然后設置destructor函數為destr_function。?

注銷一個TSD采用如下API:?

int pthread_key_delete(pthread_key_t key);

這個函數并不檢查當前是否有線程正使用該TSD,也不會調用清理函數(destr_function),而只是將TSD釋放以供下一次調用pthread_key_create()使用。在LinuxThreads中,它還會將與之相關的線程數據項設為NULL(見"訪問")。

三. 訪問?
TSD的讀寫都通過專門的Posix Thread函數進行,其API定義如下:?
int pthread_setspecific(pthread_key_t key, const void *pointer);?
void * pthread_getspecific(pthread_key_t key) ;

寫入(pthread_setspecific())時,將pointer的值(不是所指的內容)與key相關聯,而相應的讀出函數則將與key相關聯的數據讀出來。數據類型都設為void *,因此可以指向任何類型的數據。
在LinuxThreads中,使用了一個位于線程描述結構(_pthread_descr_struct)中的二維void *指針數組來存放與key關聯的數據,數組大小由以下幾個宏來說明:

?#define PTHREAD_KEY_2NDLEVEL_SIZE 32?
#define PTHREAD_KEY_1STLEVEL_SIZE \?
((PTHREAD_KEYS_MAX + PTHREAD_KEY_2NDLEVEL_SIZE - 1)?
/ PTHREAD_KEY_2NDLEVEL_SIZE)?
其中在/usr/include/bits/local_lim.h中定義了PTHREAD_KEYS_MAX為1024,因此一維數組大小為32。而具體存放的位置由key值經過以下計算得到:
idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE?
idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE?

也就是說,數據存放與一個32×32的稀疏矩陣中。同樣,訪問的時候也由key值經過類似計算得到數據所在位置索引,再取出其中內容返回。?

四. 使用范例?
以下這個例子說明如何使用這一機制達到存儲線程私有數據的目的。?

[cpp]?view plaincopy
  • #include?<stdio.h>???
  • #include?<pthread.h>???
  • ??
  • pthread_key_t?key;???
  • ??
  • void?echomsg(int?t)???
  • {???
  • printf("destructor?excuted?in?thread?%d,param=%d\n",pthread_self(),t);???
  • }???
  • ??
  • void?*?child1(void?*arg)???
  • {???
  • int?tid=pthread_self();???
  • printf("thread?%d?enter\n",tid);???
  • pthread_setspecific(key,(void?*)tid);???
  • sleep(2);???
  • printf("thread?%d?returns?%d\n",tid,pthread_getspecific(key));???
  • sleep(5);???
  • }???
  • ??
  • void?*?child2(void?*arg)???
  • {???
  • int?tid=pthread_self();???
  • printf("thread?%d?enter\n",tid);???
  • pthread_setspecific(key,(void?*)tid);???
  • sleep(1);???
  • printf("thread?%d?returns?%d\n",tid,pthread_getspecific(key));???
  • sleep(5);???
  • }???
  • ??
  • int?main(void)???
  • {???
  • int?tid1,tid2;???
  • ??
  • printf("hello\n");???
  • pthread_key_create(&key,echomsg);???
  • pthread_create(&tid1,NULL,child1,NULL);???
  • pthread_create(&tid2,NULL,child2,NULL);???
  • sleep(10);???
  • pthread_key_delete(key);???
  • printf("main?thread?exit\n");???
  • return?0;???
  • }???
  • 運行結果如下:

    hello
    thread 1082350784 enter
    thread 1090739264 enter
    thread 1090739264 returns 1090739264
    thread 1082350784 returns 1082350784
    main thread exit

    給例程創建兩個線程分別設置同一個線程私有數據為自己的線程ID,為了檢驗其私有性,程序錯開了兩個線程私有數據的寫入和讀出的時間,從程序運行結果可以看出,兩個線程對TSD的修改互不干擾。同時,當線程退出時,清理函數會自動執行,參數為tid。

    轉載于:https://www.cnblogs.com/Zoran-/p/5819278.html

    總結

    以上是生活随笔為你收集整理的线程的私有数据的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。