gcc`__thread`如何工作?

如何在gcc中实现__thread ? 它只是pthread_getspecificpthread_setspecific的包装器吗?

使用我的程序使用posix API进行TLS,现在看到我的程序运行时的30%用在pthread_getspecific上,我感到很失望。 我在每个需要资源的函数调用的条目上调用它。 pthread_getspecific联优化之后,编译器似乎没有优化pthread_getspecific 。 因此,在内联函数之后,代码基本上一次又一次地搜索正确的TLS指针以获得返回的相同指针。

__thread会在这种情况下帮助我吗? 我知道C11中有thread_local ,但我所拥有的gcc还不支持它。 (但现在我看到我的gcc确实支持_Thread_local而不是宏。)

我知道我可以简单地测试并看到。 但是我现在必须去别的地方了,在我尝试重大改写之前,我想更好地了解一个function。

最近的GCC ,例如GCC 5确实支持C11及其thread_local (如果使用例如gcc -std=c11编译)。 正如FUZxxl所评论的那样,您可以使用(而不是C11 thread_local )旧版GCC支持的__thread限定符。 阅读线程本地存储 。

pthread_getspecific确实非常慢(它在POSIX库中,因此不是由GCC提供的,例如由GNU glibc或musl-libc提供 ),因为它涉及函数调用。 使用thread_local变量很可能会更快。

查看MUSL的thread/pthread_getspecific.c文件的源代码以获取实现示例。 阅读相关问题的答案 。

并且_threadthread_local (通常)并没有神奇地转换为对pthread_getspecific调用。 它们通常涉及一些特定的地址模式和/或寄存器(细节是特定于实现的,与ABI相关;在Linux上,我想由于x86-64有更多的寄存器和地址模式,它的TLS实现比在i386上更快),在编译器 , 链接器和运行时系统的帮助下 。 相反, pthread_getspecific某些实现正在使用一些内部thread_local变量(在您的POSIX线程的实现中)。

例如,编译以下代码

 #include  const extern pthread_key_t key; __thread int data; int get_data (void) { return data; } int get_by_key (void) { return *(int*) (pthread_getspecific (key)); } 

使用GCC 5.2(在Debian / Sid上)和gcc -m32 -S -O2 -fverbose-asm使用TLS为get_data提供以下代码:

  .type get_data, @function get_data: .LFB3: .cfi_startproc movl %gs:data@ntpoff, %eax # data, ret .cfi_endproc 

以及get_by_key的以下代码, 显式调用 pthread_getspecific

 get_by_key: .LFB4: .cfi_startproc subl $24, %esp #, .cfi_def_cfa_offset 28 pushl key # key .cfi_def_cfa_offset 32 call pthread_getspecific # movl (%eax), %eax # MEM[(int *)_4], MEM[(int *)_4] addl $28, %esp #, .cfi_def_cfa_offset 4 ret .cfi_endproc 

因此,使用带有__thread (或C11中的thread_local )的TLS应该比使用pthread_getspecific更快(避免调用的开销)。

请注意, thread_local是在 (C11标准头文件)中定义的便捷宏 。

gcc的__thread与C11的_Thread_local具有完全相同的语义。 您没有告诉我们您正在编程的平台,因为平台之间的实现细节会有所不同。 例如,在x86 Linux上,gcc应该将对线程局部变量的访问权限编译为具有%fs段前缀的内存指令,而不是调用pthread_getspecific