给定本机代码(C/C++),有人可以解释线程本地存储吗?它只是一个允许线程控制自己变量的生命周期的技巧,还是编译器或硬件有一些隔离/保护措施?
底层平台重要吗?
此外,关于上述内容,普通 TLS 和“光纤安全”TLS 之间有什么区别?
抱歉,我用谷歌搜索,但我只能找到如何使用 TLS(我已经知道),而不是幕后的令人讨厌的细节。
给定本机代码(C/C++),有人可以解释线程本地存储吗?它只是一个允许线程控制自己变量的生命周期的技巧,还是编译器或硬件有一些隔离/保护措施?
底层平台重要吗?
此外,关于上述内容,普通 TLS 和“光纤安全”TLS 之间有什么区别?
抱歉,我用谷歌搜索,但我只能找到如何使用 TLS(我已经知道),而不是幕后的令人讨厌的细节。
线程本地存储 (TLS) 由操作系统管理。内核中的每个线程对象都包含一个本地 TLS 插槽数组。在运行时,应用程序的代码可以调用TlsAlloc()
它需要的每个 TLS 变量(例如声明为__thread
或的变量__declspec(thread)
,取决于编译器),以将可用索引保留到 TLS 数组中。然后每个线程可以使用TlsGetValue()
和TlsSetValue()
读取/写入存储在调用线程的 TLS 数组中的这些索引处的值。使用 TLS 完成后,应用程序可以调用TlsFree()
以释放其保留的索引。
例如,在应用程序启动时,应用程序调用TlsAlloc()
一次以保留 TLS 索引 0。在随后运行的每个线程中,任何给定线程都可以调用TlsSetValue()
TLS 索引 0,并且该值将在本地为该特定线程存储,因此值存储在其他线程的 TLS 索引 0 不会受到影响。
有关详细信息,请参阅 MSDN:
纤维在螺纹内部运行。因此,在同一个线程中运行的多个纤程将为该线程共享同一个 TLS 数组。如果一个纤程在 TLS 索引 0 处设置一个值,则在同一线程中运行的所有纤程都会受到影响。Fiber-Safe TLS 只是一种编译器优化,可防止纤程缓存任何 TLS 信息,以防纤程在其生命周期内从一个线程跳转到另一个线程。
快速回答:当线程启动时,GS 段寄存器指向该线程的(大部分未记录的)OS 数据结构。此数据结构的元素之一是 64 个 PVOID 元素的数组,TLS 函数使用它来存储多达 64 个 TLS 变量。