1. 程式人生 > 其它 >C/C++ 執行緒本地儲存

C/C++ 執行緒本地儲存

Thread Local Storage

我們知道多執行緒共享同一個程序的地址空間,對全域性變數來說,某一個執行緒對其修改會影響其他所有執行緒。

如果我們需要一個變數在每個執行緒中都能訪問,並且值在每個執行緒中互不影響,這就是 Thread Local Storage(TLS,也稱 “執行緒私有資料”)。

Linux下支援兩種方式定義和使用TLS變數,具體如下表:

定義方式 支援層次 訪問方式
__thread 關鍵字 語言層面 與全域性變數完全一樣
pthread_key_create() 函式 執行庫層面

pthread_get_specific(),讀

pthread_set_specific(),寫

__thread 關鍵字

看個例子,全域性變數 var 被定義為 執行緒私有變數

#include <stdio.h>
#include <stdint.h>
#include <pthread.h>

__thread int var = 0;   // var定義為執行緒變數,每個數線擁有一份

void* worker(void* arg)  {
    for (int i = 0; i < 1e4; i++) {
        var++;
    }   
        
    printf("child thread [%lu] var(%p)=%d\n
", pthread_self(), &var, var); return 0; } int main(){ pthread_t pid1, pid2; printf("var=%d\n", var); pthread_create(&pid1, NULL, worker, (void *)0); pthread_create(&pid2, NULL, worker, (void *)1); pthread_join(pid1, NULL); pthread_join(pid2, NULL); printf(
"main thread [%lu] var(%p)=%d\n", pthread_self(), &var, var); return 0; }

執行結果

var=0
child thread [139770628466432] var(0x7f1ee2a8e6fc)=10000
child thread [139770620073728] var(0x7f1ee228d6fc)=10000
main thread [139770645350272] var(0x7f1ee3aa877c)=0

可見,主執行緒和兩個子執行緒訪問到的 var 變數地址不一樣,每個執行緒對 var 都有一份自己的拷貝,不會互相影響。

pthread_key_create() 函式

也看個例子,

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <pthread.h>

struct foo {
    int var;
};

void* worker(void* arg)  {
    pthread_key_t* key = (pthread_key_t*) arg;

    foo* ptr;
    if ((ptr = (foo*)pthread_getspecific(*key)) == NULL) {
        ptr = (foo*) malloc(sizeof(foo));   
        (void) pthread_setspecific(*key, ptr);
    }   

    for (int i = 0; i < 1e4; i++) {
        ptr->var++;
    }   
    
    printf("child thread [%lu] var(%p)=%d\n", pthread_self(), &(ptr->var), ptr->var);
    return 0;
} 

int main(){  

    pthread_key_t key;
    (void) pthread_key_create(&key, NULL);

    pthread_t pid1, pid2;  

    pthread_create(&pid1, NULL, worker, (void *)(&key));  
    pthread_create(&pid2, NULL, worker, (void *)(&key));  

    pthread_join(pid1, NULL);  
    pthread_join(pid2, NULL);  

    foo* ptr;
    if ((ptr = (foo*)pthread_getspecific(key)) == NULL) {
        printf("main thread [%lu] var null\n");
    } else {
        printf("main thread [%lu] var(%p)=%d\n", pthread_self(), &(ptr->var), ptr->var);
    }

    pthread_key_delete(key);

    return 0;
}

執行結果

child thread [140470755546880] var(0x7fc1e00008c0)=10000
child thread [140470747154176] var(0x7fc1d80008c0)=10000
main thread [140470770246240] var null

不同執行緒通過同一個key,訪問到不同的value,可以想象 Linux 的實現會是一個map,每個執行緒對應不同的value。

======專注高效能web伺服器架構和開發=====