【问题标题】:Thread local storage / Windows线程本地存储/Windows
【发布时间】:2013-08-06 19:34:17
【问题描述】:

鉴于本机代码 (C/C++),有人可以解释线程本地存储吗?它只是一种允许线程控制自己变量的生命周期的技巧,还是编译器或硬件有一些隔离/保护措施?

下属平台重要吗?

此外,就上述而言,普通 TLS 和“光纤安全”TLS 之间有什么区别?

抱歉,我搜索了谷歌,但我只能找到如何使用 TLS(我已经知道),而不是幕后令人讨厌的细节。

【问题讨论】:

标签: windows multithreading winapi thread-local-storage


【解决方案1】:

线程本地存储 (TLS) 由操作系统管理。内核中的每个线程对象都包含一个本地 TLS 插槽数组。在运行时,应用程序的代码可以为它需要的每个 TLS 变量(例如声明为 __thread 或 __declspec(thread) 的变量,取决于编译器)调用 TlsAlloc(),以将可用索引保留到 TLS 数组中。然后每个线程可以使用TlsGetValue() 和TlsSetValue() 来读取/写入存储在调用线程的TLS 数组中这些索引处的值。使用 TLS 完成后,应用可以调用 TlsFree() 来释放其保留的索引。

例如,在应用启动时,应用调用TlsAlloc() 一次以保留 TLS 索引 0。在随后运行的每个线程中,任何给定线程都可以为 TLS 索引 0 调用 TlsSetValue(),并且该值将存储在本地对于该特定线程,因此其他线程存储在 TLS 索引 0 处的值不会受到影响。

更多详情请参考 MSDN:

Thread Local Storage

纤维在线程内部运行。因此,在同一线程中运行的多个纤程将为该线程共享相同的 TLS 数组。如果一个纤程在 TLS 索引 0 处设置一个值,则在同一线程中运行的所有纤程都会受到影响。 Fiber-Safe TLS 只是一种编译器优化,可防止纤程缓存任何 TLS 信息,以防纤程在其生命周期内从一个线程跳转到另一个线程。

【讨论】:

  • 注意 __declspec(thread) 的陷阱:“使用声明为 __declspec(thread) 的变量的后果”blogs.msdn.com/b/oldnewthing/archive/2010/11/22/10094489.aspx
  • 谢谢。操作系统级别的强制执行是否意味着任何类型的安全性,例如通过在进程空间中四处寻找来防止其他线程看到局部变量?我没有一个很好的例子来说明为什么需要这样做,但我只是想让你理解“由操作系统管理”是什么意思。
  • TLS 数组在内核线程对象中是私有的。 “由操作系统管理”就是这个意思。操作系统分配和管理数组,应用程序不能直接访问它,只能通过 TLS 函数访问数组的内容。一个线程可以戳穿另一个线程的 TLS 数据吗?理论上,是的,如果您使用未记录的 API 和直接内存访问。这样做值得吗?不。它违背了 TLS 的目的。
【解决方案2】:

快速回答:当线程启动时,GS 段寄存器指向该线程的(大部分未记录的)OS 数据结构。此数据结构的元素之一是包含 64 个 PVOID 元素的数组,TLS 函数使用它来存储多达 64 个 TLS 变量。

【讨论】:

  • 似乎很多 Windows 结构都没有记录,尽管 Windows 从 80 年代就已经存在,而我们现在是 2014 年,它仍然没有记录?!
  • @farmdve:通常最好不要公开记录内部实现细节,因为这使得以后进行任何更改变得更加困难。 MS 中的相关团队将拥有自己的文档,当然,它只是不向公众提供。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-08
  • 1970-01-01
  • 2011-01-04
  • 2015-05-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多