为什么需要TLS(Thread Local Storage)?
[原文:http://www.cnblogs.com/neoragex2002/archive/2004/12/10/75329.html]
线程局部存储(TLS)是Win32提供的一种底层基础技术,用于将某些数据和一特定线程关联起来,即,这些数据为关联线程所独有(私有)。初看上去,有 点郁闷了:既然每个线程都有自己的私有堆栈,那么还要整个TLS做劳什子?线程的私用数据全放堆栈里不就得了?...... 然而事情并不是那么简单的=) 下面举个具体的例子。
所谓堆栈,相当于是一个历史记录,里面存储的数据(函参、返回值、调用上下文)与函数调用顺序有着密不可分的联系。假设有某线程ThreadProc的伪码是这样写滴:
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
其调用链很清楚,ThreadProc->A->B->C然后再返回,调用链中的每个函数都引用了a并且修改了a的值,注意到,“全局 变量”a是没有存储在线程堆栈中的,但是与此同时我们想让a成为线程所独有的数据,即,不期望发生同时多个ThreadProc线程的实例访问并修改同一 个全局变量,导致运行结果不确定的情况(运行结果的不确定源于线程调度顺序、调度时被中断位置的不确定),该怎么办?用TLS。
慢,事情还没有完!隔壁的某位先生马上抢白我了(绝杀状):“上述解释还是无法令人满意!——这个程序我还可以这样写,照样不需要TLS!” 下面一起来看看这个无需TLS的程序是怎么写的:
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
汗....本来想偷点懒de.....^^ 没办法了,看来偶也得放绝杀了。是的,我承认隔壁的先生的确是善于思考,通过copy一份全局变量a的值到线程自己的私有局部变量aa、同时在调用每一个 函数时都将aa的指针作为函参的方法,几乎是完全避免了TLS的使用,也就否定了TLS存在的意义。不过,(嘿嘿,准备逆转)难道大家不觉得这种方式太烦 了吗?且不论仅仅只用到了一个线程全局量的时候就这样了,更不用说假设要用到十个八个全局量的时候场面有多壮观了;还有,调用链上每个函数都有一个函参指 针指向堆栈copy,假设是十个八个全局量、调用链又有个十层八层那该浪费多少堆栈里面的空间啊.....另外,再补充一点,为了向下兼容,例如,现有的 C标准库在Win32之前已经存在很长一段时间了,由于没有考虑多线程环境的影响,里面大量地使用了全局静态变量,C标准库不是由你我写的,当然也就没法 修改了,如果在线程体里面要使用这些“危险”函数的话,你我该怎么办?不用标准库?会被累死的......所以C/C++标准库使用了TLS,所以TLS 有其存在的价值。