執行緒的區域性儲存

2021-10-24 02:03:41 字數 3597 閱讀 7193

在前面提到多執行緒或者多程序程式設計中,都會提到乙個資源共享的問題。現在可以知道通過使用各種鎖來控制資料的共同訪問資源的問題。但在實際情況中還會有一種場景,就是每個執行緒都有自己的相同的類似的資源,這樣每個執行緒都可以控制自己的資源。就如好多孩子一起撿豆子,每人有乙個盛豆子的容器一樣,每個孩子把自己的豆子放到自己的容器中去,最後憑誰的多來判斷勝負。

執行緒區域性儲存的意思和上面的例子差不多,其實就是多個執行緒中的變數你是你的我是我的,咱們互不搭界,互不侵犯,最典型的就是vc中的getlasterror這個函式,當然它做的也不是特別好。

尤其在多個執行緒使用同乙個執行緒函式時,這種情況會更普遍,執行緒的區域性儲存在不同的平台下會有不同的方法,下面分別介紹。

在linux平台下提供了下面的幾個api介面來實現執行緒的區域性儲存:

1、建立key

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

2、刪除key,注意只是釋放執行緒使用權,並在相關執行緒置位,並未釋放資源

int pthread_key_delete(pthread_key_t key);

3、由key取值

void * pthread_getspecific(pthread_key_t key);

4、由key設值

int pthread_setspecific(pthread_key_t key, const void * value);

5、gcc提供的關鍵字__thread來定義變數

下面看乙個簡單的例子:

#include #include static pthread_key_t key;

static pthread_once_t once = pthread_once_init;

__thread int local = 9;

int value = 100;

static void createkey(void)

void* threadfunc(void* param)

local++;

local++;

int * d = (int*)pthread_getspecific(key);

std::cout<<"thread is is:"<<(void*)pthread_self()<<"value is:"<<* d《執行結果:

thread is is:139655031064320value is:100

thread is is:139655031064320local is:11

thread is is:139655039457024value is:100

thread is is:139655039457024local is:11

每個平台雖然都有不同,但原理卻基本相同,在windows中,每個執行緒建立是分得乙個tls索引陣列,其實就是乙個lpvoid的指標陣列,一般來說為了介面的方便性,windows上經常把一些指標宣告成通用的void*,這樣方便轉來轉去,不過這也方便崩來崩去(開個玩笑)。其實這個陣列就是為了訪問執行緒資訊塊tib的方便,每個執行緒都會維護自己的棧和一些相關的資源。而執行緒內部的區域性儲存就是這個意思,它會被tls陣列索引。

實際上可以簡單理解乙個有乙個指標,這個指標被每個執行緒分別持有,但是它指向的相關記憶體的內容不同,這樣,在每次操作此指標時,雖然名字相同,但是實際操作的資料並不同,這樣就會產生區域性儲存這種功能。它可以通過下面的幾步來完成:

1、主程序內呼叫tlsalloc()函式,得到序號:

dword index = tlsalloc();

2、分配執行緒儲存空間

void* pvalue = localalloc(lptr,sizeof(int));

再通過tlssetvalue()函式把這塊位址儲存上面的分配的索引中:

tlssetvalue( index, pvalue);

3 、操作

lpvoid lpvdata = tlsgetvalue(index);

__declspec( thread ) int var_name;
這些使用要非常注意不同的windows版本中的不同的情況,小心應付。在高版本或者服務平台上可能無法使用或者得換相關的標頭檔案等。

看一下下面的大概例子(有些平台無法使用,所以只給了乙個原型):

#include #include uint winapi threadfunc(lpvoid params)

int win_local()

//等待工作執行緒

::waitformultipleobjects(5, handle, true, infinite);

for (int i = 0; i < 5; i++)

//釋放tls

::tlsfree(index);

return 0;

}

執行結果:

cur thread id: cur thread id: 130828cur thread id: cur value:cur thread id: 79080102696104344cur value:cur value:0000000000000009

cur thread id: 136032cur value:cur value:0000000000000009

0000000000000009

0000000000000009

0000000000000009

與tls(thread local storage)類似,在c++11中提供了乙個thread_local的宣告符,用它宣告的變數變數每乙個執行緒都有自己的該全域性變數的例項(instance),該例項的變數名就是全域性變數名稱。

//以前:

int t = 0;

std::mutex m;

void test_mutex()

void test_func()

//現在看:

thread_local int tlocal = 0;

void test_thread_local()

void test_local_func()

int main()

執行結果:

t value is:0

t value is:1

t value is:2

tlocal value is:1

tlocal value is:1

tlocal value is:0

這個結果可以看到,在使用鎖的情況下,資料順序公升級,但如果使用本地變數,本地則自動公升級,如果大家感興趣,可以多增加幾個執行緒就發現了,或者在自己的執行緒中多呼叫幾次,對比一下,會更清楚。

執行緒的區域性變數一般來說可以用三種型別的變數來定義,即具名空間下的全域性變數、類的靜態成員變數和區域性變數。其實執行緒區域性儲存的引入是和c++中的變數生存週期(automatic,static,dynamic,thread)有關係,其中只有thread_local是具有執行緒週期的。明白了各種資料型別的定義和關係,才能在實際的應用場景中游刃有餘的解決相關的實際問題,每天多學一點,多總結一點,每天多進步一點!

苟日新,日日新!

執行緒區域性儲存 TLS

本來想通過tid為索引建個表來實現該功能,沒想到已經有現成的機制。單個執行緒的特有資料,介於全域性變數和區域性變數之間。linux 方法一 int pthread key create pthread key t key,void destructor void int pthread key de...

TLS執行緒區域性儲存

為執行緒單獨提供的私有空間 隱式tls thread int number 顯式tls pthread key create pthread getspecific pthread setspecific pthread key delete 隱式tls declspec thread int nu...

執行緒區域性儲存(TLS)的使用

將執行緒的私有資料 區域性儲存的資料 共享,以供本程序中的其它執行緒使用。l 適用情形 執行緒區域性儲存適用於多執行緒共享資料,而又不需要同步的情形。執行緒同步的開支比較大。l 原理 在每個執行緒中有乙個儲存區域,該儲存區域有64個slot 資料槽 可以通過該slot的索引值 乙個dword數值 獲...