线程本地存储进程
Posted
技术标签:
【中文标题】线程本地存储进程【英文标题】:Thread local storage processes 【发布时间】:2021-06-29 21:16:17 【问题描述】:我正在查看有关线程本地存储的文档,但我认为它写得不好。
https://docs.microsoft.com/en-us/windows/win32/procthread/thread-local-storage
似乎他们编写文档的方式是零星的,他们将提供一个发生的事件,然后下一句他们将提供有关在此事件之前需要发生什么的信息。然后另一个事件发生了,他们会解释在这个事件之前需要发生什么。但顺序事件的链条尚不清楚。通常他们会在一个句子中提供一个对象,然后下一个句子谈论另一个对象,同时透露有关该对象的更多细节。
但据我了解,有一个全局索引,其中索引具有关联的数据,一个线程分配索引,然后其他线程可以访问它。当创建线程时,会生成一个称为 TLS 槽的 LPVOID 值数组。然后将与索引关联的数据存储在此数组中。
我的困惑在于最后一部分,它说线程分配内存块,然后将指向这些内存块的指针存储在 LPVOID TLS 插槽中。并且指向内存块的指针是从 TLS 插槽中检索的,同时存储在局部变量中。
我的问题是 TLS 插槽中究竟存储了哪些值、内存地址或实际数据值?如果是内存地址指针,我假设这些地址被访问以获取存储在内存块中的值。
分配 2 个内存空间是否也正确,一个用于 LPVOID 数组值,另一个用于索引的内存空间块?它说如果使用大量索引和LPVOID数组,最好分配一个单独的内存空间以避免占用TLS插槽,这就是内存块所指的,数据存储在内存块中,地址存储在插槽中以避免插槽中的数据过载?
阅读文档就像一个难题,如果有人可以提供帮助,我将不胜感激。我已经展示了他们提供的图解结构的图像。
enter image description here
【问题讨论】:
【参考方案1】:TLS 槽 - 图中的槽 - 是线程信息块中 LPVOID 大小的变量的固定大小数组。通常它们用于存储指针。这里存储的指针指向的内存不是线程本地的,而是正常分配的。然而,由于线程将指针存储在 TLS 插槽中,该插槽 是线程本地的,因此内存实际上是线程私有的。
如果您谈论的是原始 Windows API 而不是编译器辅助的线程本地存储,则存储在 TLS 中的数据不是指针的要求,它可以是纯数值(与 LPVOID 之间的转换),如果这对您的场景很有意义。
【讨论】:
感谢您的清晰解释。接受的答案,喜欢这个名字:)【参考方案2】:我的问题是 TLS 插槽中究竟存储了哪些值、内存地址或实际数据值?
两者都有!
链接中的以下段落涵盖了这一点:
如果与索引关联的数据适合 LPVOID 值,您可以将数据直接存储在 TLS 槽中。但是,如果您以这种方式使用大量索引,则最好分配单独的存储,合并数据,并尽量减少 TLS 插槽的数量。
这是一种称为 Small Object O优化的技术,其中一些存储可以是值或指向其他一些内存位置,具体取决于所存储内容的大小。该段只是一种迂回的说法:
“如果可以,我们建议您使用 SOO,因为系统不会查看指针的值。”
如果是内存地址指针,我假设这些地址被访问以获取存储在内存块中的值。
正确,但前提是您选择将存储空间用作指针。
分配 2 个内存空间是否也正确,一个用于 LPVOID 数组值,另一个用于索引的内存空间块?它说如果使用大量索引和LPVOID数组,最好分配一个单独的内存空间以避免占用TLS插槽,这就是内存块所指的,数据存储在内存块中,地址存储在插槽中以避免插槽中的数据过载?
不是真的,它只是一个大的指针表。如果您希望指针指向某个有意义的地方,则需要分配一些要指向的内存,但该分配没有什么特别之处。
【讨论】:
【参考方案3】:如果您打算编写 C++ 并且您不需要专门使用 Win32 函数,那么您应该使用 C++11 thread_local
。见https://en.cppreference.com/w/cpp/keyword/thread_local
这是便携的,使用起来更容易。
【讨论】:
以上是关于线程本地存储进程的主要内容,如果未能解决你的问题,请参考以下文章