C++编译器如何在C++0x中实现线程局部存储?

19

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

我在谷歌上搜索了这个问题,但是没有找到相关的内容。

有没有人有关于这个问题的资料?


C++标准没有(或者非常少)实现细节。 - Martin York
这可能会有所帮助:http://www.akkadia.org/drepper/tls.pdf - Julio Guerra
3个回答

22

请阅读维基百科条目

线程本地存储并不是特定于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是什么的问题。如果程序是静态链接的,则可以将其视为指向程序中声明为元素的所有线程本地存储变量的大型结构体的指针。这是一个过度简化,但您可以得到一般想法。

访问线程本地存储变量显然不仅仅是直接的内存读写。它可能会涉及到更多的操作。如果您在特定函数中要频繁使用线程本地/特定存储,请先将线程本地存储指针复制到本地变量中。


3
你已经回答了应用程序开发人员如何实现TLS,但未说明编译器和加载器如何处理C++0x的thread_local关键字。 - doron
6
编译器和加载器要么使用操作系统提供的API,要么自己实现映射技术,而无需应用程序员编写任何代码。 - Doug

8
全局变量(或可写静态数据-WSD)通常存储在与堆栈、堆和代码不同的内存块中。 WSD块在可执行文件的代码开始运行之前创建和初始化。
C ++ 0x引入了 thread_local 关键字,它确保为每个线程创建单独的全局变量实例。问题在于每个线程需要加载不同的块。
下一个困难是变量的地址在链接时不固定,并且对于每个线程都不同。
解决此问题的两种方法。一种是编译器生成函数调用以获取正确的块,另一种是更改ABI以将TLS块存储在处理器寄存器之一中。然后可以使用偏移量访问正确的 thread_local 变量。
这与库支持不同,其中操作系统存储单个 void * 值,该值可用于存储已在进程堆上分配的线程本地块的指针。
如果您想了解详细信息,请在此处查看。

0
你可以使用boost::thread在不同平台上处理TLS。每个平台的实现都在代码中,这应该能帮助你了解不同系统如何处理这个领域。

1
在 C++0x 中,编译器使用 thread_local 关键字支持 TLS。 - doron
使用 boost 很好,但是需要注意的是一些编译器确实存在问题。请参考 http://gcc.gnu.org/onlinedocs/gcc-3.3.1/gcc/Thread-Local.html 。 - Tony Delroy
3
C++0x新增了一个关键字thread_local,与gcc中的__thread具有完全相同的功能。 - doron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接