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。

 

posted @ 2021-07-13 16:13  如果的事  阅读(1110)  评论(0编辑  收藏  举报