• 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
    ", pthread_self(), &var, var);
        return 0;
    } 
    
    int main(){  
        pthread_t pid1, pid2;  
        printf("var=%d
    ", 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
    ", 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
    ", 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
    ");
        } else {
            printf("main thread [%lu] var(%p)=%d
    ", 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服务器架构和开发=====
  • 相关阅读:
    Python 简单的方法爬取b站dnf视频封面
    Opencv学习(一)
    某个代码
    2017年江西理工大学C语言程序设计竞赛(高级组)
    2017年江西理工大学C语言程序设计竞赛(初级组)
    两数相除
    华东交通大学2017年ACM“双基”程序设计竞赛 1009
    华东交通大学2017年ACM“双基”程序设计竞赛 1005
    UE4联机多人游戏基本设置
    菜鸟学习物联网---辨析基于Andriod 5.1,Linux,Windows10开发Dragon Board 410c板
  • 原文地址:https://www.cnblogs.com/chenny7/p/15006904.html
Copyright © 2020-2023  润新知