zoukankan      html  css  js  c++  java
  • [原创] 为什么需要TLS(Thread Local Storage)?

    线程局部存储(TLS)是Win32提供的一种底层基础技术,用于将某些数据和一特定线程关联起来,即,这些数据为关联线程所独有(私有)。初看上去,有点郁闷了:既然每个线程都有自己的私有堆栈,那么还要整个TLS做劳什子?线程的私用数据全放堆栈里不就得了?...... 然而事情并不是那么简单的=) 下面举个具体的例子。

    所谓堆栈,相当于是一个历史记录,里面存储的数据(函参、返回值、调用上下文)与函数调用顺序有着密不可分的联系。假设有某线程ThreadProc的伪码是这样写滴:

    int a=100
     
    CreateThread(ThreadProc,NULL); 
     
    void ThreadProc(void* lpvoid) 
        print(a
    ++); 
        A();     
    }
     
     
    void A() 
        print(a
    ++); 
        B(); 
    }
     
     
    void B() 
        print(a
    ++); 
        C(); 
    }
     
     
    void C() 
        print(a
    ++); 
    }

    其调用链很清楚,ThreadProc->A->B->C然后再返回,调用链中的每个函数都引用了a并且修改了a的值,注意到,“全局变量”a是没有存储在线程堆栈中的,但是与此同时我们想让a成为线程所独有的数据,即,不期望发生同时多个ThreadProc线程的实例访问并修改同一个全局变量,导致运行结果不确定的情况(运行结果的不确定源于线程调度顺序、调度时被中断位置的不确定),该怎么办?用TLS。

    慢,事情还没有完!隔壁的某位先生马上抢白我了(绝杀状):“上述解释还是无法令人满意!——这个程序我还可以这样写,照样不需要TLS!” 下面一起来看看这个无需TLS的程序是怎么写的:

    int a=100
     
    CreateThread(ThreadProc,
    &a); 
     
    void ThreadProc(void* lpvoid) 
        
    int aa=*((int*)lpvoid); 
        
    int* pa=&aa;     
     
        print((
    *pa)++); 
        A(pa);     
    }
     
     
    void A(int* pa) 
        print((
    *pa)++);     
        B(pa); 
    }
     
     
    void B(int* pa) 
        print((
    *pa)++);     
        C(pa); 
    }
     
     
    void C(int* pa) 
        print((
    *pa)++);     
    }
      

    汗....本来想偷点懒de.....^^ 没办法了,看来偶也得放绝杀了。是的,我承认隔壁的先生的确是善于思考,通过copy一份全局变量a的值到线程自己的私有局部变量aa、同时在调用每一个函数时都将aa的指针作为函参的方法,几乎是完全避免了TLS的使用,也就否定了TLS存在的意义。不过,(嘿嘿,准备逆转)难道大家不觉得这种方式太烦了吗?且不论仅仅只用到了一个线程全局量的时候就这样了,更不用说假设要用到十个八个全局量的时候场面有多壮观了;还有,调用链上每个函数都有一个函参指针指向堆栈copy,假设是十个八个全局量、调用链又有个十层八层那该浪费多少堆栈里面的空间啊.....另外,再补充一点,为了向下兼容,例如,现有的C标准库在Win32之前已经存在很长一段时间了,由于没有考虑多线程环境的影响,里面大量地使用了全局静态变量,C标准库不是由你我写的,当然也就没法修改了,如果在线程体里面要使用这些“危险”函数的话,你我该怎么办?不用标准库?会被累死的......所以C/C++标准库使用了TLS,所以TLS有其存在的价值。

    隔壁的先生不啃声了。一句话,存在,总得有道理=)
  • 相关阅读:
    2021.6.7
    2021.6.4
    2021.6.3
    2021.6.2 团队第二阶段冲刺第十天
    2021.6.1 团队第二阶段冲刺第九天
    2021.5.31 团队第二阶段冲刺第八天
    2021.5.30 团队第二阶段冲刺第七天
    逻辑卷的使用
    磁盘阵列
    磁盘配额
  • 原文地址:https://www.cnblogs.com/neoragex2002/p/75329.html
Copyright © 2011-2022 走看看