c ++编译器如何在C ++ 0x中实现线程本地存储
我在谷歌搜索过这个。但我找不到任何关于此事的内容。
有没有人对此有任何材料?
答案 0 :(得分:13)
线程本地存储不是C ++特有的。有时它会使用不同的名称,例如“TLS”(只是线程本地存储的缩写)或“特定于线程的存储”(TSS)。
大多数操作系统都提供API来访问每线程存储。例如,Windows的“{3}”以“TLS”开头。在引擎盖下,Win32为各种线程数据保留了一个特殊区域,包括用户线程本地存储,可通过特定的CPU寄存器(x86上的FS)访问。 Linux通过pthread API提供特定于线程的存储,名称为bunch of API functions,这些通常使用类似的技术实现。
操作系统可能根本不提供任何支持。但是,如果操作系统通过API提供进程唯一的线程ID,那么C ++运行时库可以在内部维护概念上类似std::map<thread_id, per_thread_storage>
的内容。当然,那就是per_thread_storage
的问题。如果一个程序是静态链接的,它可能就像一个指向一个大结构的指针,所有的线程本地存储变量都在程序中声明为元素。这是一个过于简单化,但你得到了一般的想法。
访问线程本地存储变量显然不仅仅是直接内存读取或写入。它可能比这更具参与性。如果要在特定函数中大量使用线程本地/特定存储,我建议您先将线程局部存储指针复制到局部变量中。
答案 1 :(得分:5)
全局变量(或可写静态数据 - WSD)通常存储在与堆栈,堆和代码分开的内存块中。在可执行代码开始运行之前,创建并初始化WSD块。
C ++ 0x引入了thread_local
关键字,确保为每个线程创建一个单独的全局变量实例。问题是需要为每个线程加载不同的块。
下一个难点是变量的地址在链接时并不固定,并且每个线程都不同。
这个问题有两种解决方法。一种是让编译器生成函数调用以获得正确的块,而另一种是更改ABI以将TLS块存储在一个处理器寄存器中。然后,这可以与偏移一起使用以访问正确的thread_local
变量。
这不同于库支持,其中OS存储单个void*
值,可以使用该值存储指向已在进程堆上分配的线程本地块的指针。
如果您希望血腥细节显示here。
答案 2 :(得分:0)
您可以使用boost::thread在不同平台上轻松处理TLS。每个实现都在代码中,应该可以帮助您了解不同系统如何处理这个领域。