gpt4 book ai didi

c++ - 为什么线程本地存储没有用页表映射实现?

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:57:44 25 4
gpt4 key购买 nike

我希望使用 C++11 thread_local将被频繁访问的每线程 bool 标志的关键字。

但是,大多数编译器似乎使用一个表来实现线程本地存储,该表将整数 ID(槽)映射到当前线程上的变量地址。这种查找将发生在性能关键代码路径中,因此我对其性能有些担忧。

我希望实现线程本地存储的方式是根据线程分配由不同物理页面支持的虚拟内存范围。这样一来,访问该标志的成本将与任何其他内存访问的成本相同,因为 MMU 负责映射。

为什么主流编译器都不以这种方式利用页表映射?

我想我可以用 mmap 实现我自己的“特定于线程的页面”在 Linux 和 VirtualAlloc在 Win32 上,但这似乎是一个非常常见的用例。如果有人知道现有的或更好的解决方案,请指出它们。

我还考虑过存储 std::atomic<std::thread::id>在每个对象中代表事件线程,但分析显示检查 std::this_thread::get_id() == active_thread相当昂贵。

最佳答案

在 Linux/x86-64 上,线程本地存储是通过特殊的段寄存器 %fs 实现的(根据 x86-64 ABI 第 23 页...)

所以下面的代码(我用的是C+GCC扩展__thread语法,但是和C++11的thread_local是一样的)

__thread int x;
int f(void) { return x; }

被编译(使用 gcc -O -fverbose-asm -S)成:

         .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_getspecific确实通过了一个表,但是一旦你有了 TLS 就几乎没用了。

顺便说一句,根据定义,所有 threads在同一process同享address spacevirtual memory , 因为进程有自己的单个 address space . (请参阅 /proc/self/maps 等...有关 /proc/ 的更多信息,请参阅 proc(5),以及 mmap(2);C++11 线程库基于 pthreads,使用 clone(2) 实现)。所以“线程特定的内存映射”是一个矛盾:一旦任务(由内核调度程序运行的东西)有自己的地址空间,它就被称为进程(而不是线程)。 threads 的定义特征在同一个进程中共享一个公共(public)地址空间(以及一些其他实体,如文件描述符)。

关于c++ - 为什么线程本地存储没有用页表映射实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26437921/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com