linux - 线程本地存储变量的地址

标签 linux gcc thread-local-storage

好的,说我有

__thread int myVar;

然后我将 &myVar 从一个线程传递到另一个……如果数据是真正的“本地”,那么 1 个线程的 TLS 存储可能不会映射到其他线程的地址空间,事实上,您可能会争论它不应该是。这将导致 SIGSEGV 或其他东西。但是,系统可以将相同的地址映射到不同的页面。这是 Linux 对 .tbss/.tdata 所做的吗?在那种情况下,传递变量的地址会给你错误的变量地址!你会得到你自己的本地副本,而不是你试图传递的副本。或者,是否所有内容都共享并映射到不同的虚拟地址 - 允许您传递 __thread 变量的地址?

显然,如果有人试图通过传递其地址来将线程本地存储传递给另一个线程,则应该受到殴打和鞭打。还有一百万种其他方法 - 例如复制到任何其他变量!但是,我很好奇是否有人知道..

  1. 官员描述了这种情况下的行为
  2. 当前的 GCC/Linux 实现细节

-- 埃文

最佳答案

至少对于 x86,TLS 是使用段寄存器执行的。默认段寄存器 %ds 隐含在寻址内存的指令中。访问 TLS 时,线程使用另一个段寄存器 - %gs 用于 i386 和 %fs 用于 x86-64 - 在调度线程时保存/恢复,就像其他寄存器处于上下文切换中。

所以一个进程范围的变量可以通过类似的方式访问:

mov (ADDR) -> REG ; load memory `myVar` to REG.

这是隐含的:

mov %DS:(ADDR) -> REG

对于 TLS,编译器生成:

mov %FS:(ADDR) -> REG ; load thread-local address `myVar` to REG.

实际上,即使变量的地址在不同的线程中看起来是相同的,例如,

fprintf(stdout, "%p\n", & myVar); /* in separate threads... */

事实上每个线程都使用不同的段寄存器值,这意味着它们映射到物理内存的不同区域。

Windows(它可能会互换 %fs%gs 的角色 - 不确定)和 OS X 使用相同的方案。至于其他架构,有一个深入的technical guide到 ELF ABI 的 TLS。它缺少对 ARM 架构的讨论,但包含有关 IA-64 和 Alpha 的详细信息,因此它显示了它的年代。

关于linux - 线程本地存储变量的地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24793556/

相关文章:

linux - 将 bash `ls` 输出转换为 json 数组

linux - 动态创建文件

c - C 中 long long 的备用格式说明符

c++ - gcc 是否保证对 volatile 整数的对齐访问是原子的?

c++ - 如何分配线程本地存储?

c - 了解管道、重定向和 IPC

linux - 如何以另一个用户的身份使用 sudo 在 bash 子shell 中执行一系列命令?

c - gcc 对 alloca 的处理是怎么回事?

c - "thread local storage"和 "thread specific storage"的区别

c++11 - 使用 thread_local 时 gcc 4.8.1 中的内存泄漏?