在 Linux/x86-64 上,线程本地存储是通过特殊的段寄存器实现的%fs
(per x86-64 ABI https://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf第 23 页...)
所以下面的代码(我使用C + GCC扩展__thread
语法,但与C++11相同thread_local
)
__thread int x;
int f(void) { return x; }
被编译(与gcc -O -fverbose-asm -S
) into:
.text
.Ltext0:
.globl f
.type f, @function
f:
.LFB0:
.file 1 "tl.c"
.loc 1 3 0
.cfi_startproc
.loc 1 3 0
movl %fs:x@tpoff, %eax # x,
ret
.cfi_endproc
.LFE0:
.size f, .-f
.globl x
.section .tbss,"awT",@nobits
.align 4
.type x, @object
.size x, 4
x:
.zero 4
因此,与您担心的相反,在 Linux/x86-64 上访问 TLS 非常快。它并不完全作为一个表来实现(而是由内核和运行时管理%fs
段寄存器指向线程特定的内存区域,编译器和链接器管理那里的偏移量)。然而,老pthread_getspecic http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_setspecific.html确实通过了一个表,但是一旦你有了 TLS,几乎就没用了。
BTW, 根据定义, all threads http://en.wikipedia.org/wiki/Thread_%28computing%29在相同的process http://en.wikipedia.org/wiki/Process_%28computing%29分享相同的地址空间 http://en.wikipedia.org/wiki/Address_space in 虚拟内存 http://en.wikipedia.org/wiki/Virtual_memory,因为一个进程有自己的单一地址空间 http://en.wikipedia.org/wiki/Virtual_memory. (see /proc/self/maps
等等...看看proc(5) http://man7.org/linux/man-pages/man5/proc.5.html了解更多关于/proc/
,并且mmap(2) http://man7.org/linux/man-pages/man2/mmap.2.html; C++11线程库基于pthreads https://computing.llnl.gov/tutorials/pthreads这是使用实现的clone(2) http://man7.org/linux/man-pages/man2/clone.2.html)。所以“线程特定的内存映射”是一个矛盾:一旦一个任务(由内核调度程序运行的东西)拥有自己的地址空间,它就被称为进程(而不是线程)。的定义特征threads https://computing.llnl.gov/tutorials/pthreads/#Thread在同一进程中是共享一个公共地址空间(以及一些其他实体,例如文件描述符)。