17

c++编译器如何在C++0x中实现线程本地存储

我在谷歌搜索过这个。但我找不到任何关于此的信息。

有人有这方面的资料吗??

4

3 回答 3

21

阅读Wikipedia 条目

线程本地存储并不是 C++ 特有的。有时它有不同的名称,例如“TLS”(只是线程本地存储的缩写)或“线程特定存储”(TSS)。

大多数操作系统都提供 API 来访问每个线程的存储。例如,Windows 有一堆以“TLS”开头的 API 函数。在底层,Win32 为各种每线程数据保留了一个特殊区域,包括用户线程本地存储,可通过特定的 CPU 寄存器(x86 上的 FS)访问。Linux 通过 pthread API 提供特定于线程的存储,名称类似于pthread_key_create,这些通常使用类似的技术实现。

操作系统可能根本不提供任何支持。但是,如果操作系统通过 API 提供进程唯一的线程 ID,那么 C++ 运行时库可以在概念上维护一些类似于std::map<thread_id, per_thread_storage>内部的东西。当然,还有一个问题是什么per_thread_storage。如果一个程序是静态链接的,它可能只是一个指向一个大结构的指针,其中所有在程序中声明为元素的线程局部存储变量。这是一个过度简化,但你明白了一般的想法。

访问线程局部存储变量显然不仅仅是直接的内存读取或写入。它可能比这更复杂。如果您要在特定函数中大量使用线程局部/特定存储,我建议您首先将线程局部存储指针复制到局部变量中。

于 2010-09-17T11:00:48.187 回答
8

全局变量(或可写静态数据 - WSD)通常存储在与堆栈、堆和代码分开的内存块中。WSD 块是在可执行文件的代码开始运行之前创建和初始化的。

C++0x 引入了thread_local确保每个线程创建一个单独的全局变量实例的关键字。问题是每个线程需要加载不同的块。

下一个难点是变量的地址在链接时不是固定的,每个线程都不一样。

有两种方法可以解决这个问题。一种是让编译器生成一个函数调用以获得正确的块,而另一种是更改 ABI 以将 TLS 块存储在一个处理器寄存器中。然后可以将其与偏移量一起使用以访问正确的thread_local变量。

这与库支持不同,其中操作系统存储单个void*值,该值可用于存储指向已在进程堆上分配的线程本地块的指针。

如果你想要血淋淋的细节看这里

于 2010-09-17T11:16:13.663 回答
0

您可以使用boost::thread在不同平台上可移植地处理 TLS。每个的实现都在代码中,应该可以帮助您了解不同的系统如何处理该区域。

于 2010-09-17T11:16:21.107 回答