【问题标题】:C++ - Where are thread_local variables stored?C++ - thread_local 变量存储在哪里?
【发布时间】:2018-02-01 12:08:43
【问题描述】:

我试图了解 thread_local 限定符的工作原理以及实际变量的存储位置?这是在 C++ 上的。

假设我有一个包含多个成员变量的类。该类的一个对象在堆上实例化,并且该对象在 2 个线程之间共享。使用适当的锁定机制来确保两个线程不会同时踩到一个成员变量。

需要线程来跟踪少数线程特定的项目。所以我想在与 Class 声明相同的头文件中创建一个 thread_local 变量。据我了解,两个线程都会得到自己的这个变量的副本,对吗?线程局部变量究竟存储在内存中的什么位置?如果是数据段,那么在执行过程中,正确的变量究竟是如何被拾取的?

【问题讨论】:

  • 我认为这是实现定义的。
  • any 变量的存储位置一样,它是特定于实现的。
  • 常见的实现有什么作用?说gcc。一般来说,我们可以考虑将使用 malloc/new 的动态分配放在堆上,将局部变量和函数参数放在堆栈上。大多数实现都坚持这一点。在这种情况下,thread_local 变量去哪儿了?
  • @Ben 线程局部变量是非常特定于实现的,因为底层操作系统线程设施不同(参见 Windows,POSIX)。
  • 它的工作原理是魔法。想象一下,某处有一个普通的全局(互斥或以其他方式受到保护)std::map<std::thread::id,void*> TLS。您可以使用TLS[std::this_thread::get_id()] 检索您的 TLS。实际上,x86 上的实现使用 %fs(或 32 位上的 %gs)作为 TLS 段的基础。这真的很重要吗?

标签: c++ c++11 thread-local


【解决方案1】:

在 64 位 Windows 的情况下,可以通过 GS 选择器寄存器访问 TLS,使用每个线程的单独物理地址空间(在 CreateThread() 期间分配),尽管 Visual Studio 可能会将 TLS 映射到进程/线程虚拟地址空间,每个线程获得不同的虚拟地址,因为它是每个线程的不同物理地址。您可以通过使用调试器进入 rand() 来查看反汇编代码,以查看它如何访问作为 TLS 变量的种子。

【讨论】:

    【解决方案2】:

    1.据我了解,两个线程都会获得自己的这个变量的副本,对吗?
    是的。每个线程都有自己的 thread_local 变量副本。
    2。线程局部变量究竟存储在内存中的什么位置?如果是数据段,在执行过程中,正确的变量究竟是如何被拾取的?
    thread_local 是线程本地存储概念的实现。 TLS 被实现为带有每个线程对象的插槽表。每个线程都有自己的表副本。例如,在 TLS 的 Windows 实现中,该表位于线程的线程信息块中。当一个全局/静态变量被声明为 thread_local 时,它将与每个线程的表槽在相同的偏移量处相关联。当线程访问 thread_local 变量然后使用当前线程上下文时,线程自己的与该线程对象中的表槽关联的变量的副本被访问。请查看此链接以获取有关 TLS 实施的更多详细信息。 https://en.wikipedia.org/wiki/Thread-local_storage

    【讨论】:

    • 数据是否存储在实际表中?这看起来很奇怪,好像你有不同大小的 thread_local 对象,没有一致的“槽”大小。如果表不存储对象本身,而只是指向对象的指针,那么对象本身在哪里分配?在任何一种情况下,表本身在内存中的分配位置/方式是什么,以便它可以处理大量不同数量(和大小?)的潜在 thread_local 对象?
    【解决方案3】:

    您的描述听起来您想将某些非静态成员 var 标记为 thread_local。这是不允许的。

    thread_local 有点像 static(全局),但特定于每个线程,而 static 在所有线程之间共享

    每个线程都有自己的内存范围。例如自己的堆栈。

    http://en.cppreference.com/w/cpp/language/storage_durationReferen

    【讨论】:

    • 对不起,如果不清楚。我想将一个全局变量(只是在与类声明相同的头文件中声明)作为thread_lcoal。此外,两个线程都使用相同的对象实例。所以成员变量无论如何都是相同的,因此使用锁来保护。
    • 当所有线程共享同一个对象时,不需要thread_local。如果某些线程共享一个对象,您必须传递该信息,例如在线程创建时,您需要一个指向该对象的 thread_local 指针。
    • 如您所说,正在传递对象指针。该指针上没有 thread_lcoal 声明。很少有成员函数需要知道它们是从哪个线程调用的。因此在头文件中考虑一个 thread_local 全局变量。
    猜你喜欢
    • 2010-09-18
    • 2017-03-26
    • 2010-10-02
    • 2010-09-10
    • 2021-02-08
    • 2011-04-11
    相关资源
    最近更新 更多