gcc 在这里对每个线程一次 运行 这段代码做了什么?
What is gcc doing here to run this code once per thread?
我只是 运行 跨过这项技术,每个线程 运行 代码一次。我不知道它在最低级别上是如何工作的。特别是,fs
指向什么? .zero 8
是什么意思?标识符是 @tpoff
是有原因的吗?
int foo();
void bar()
{
thread_local static auto _ = foo();
}
输出(带-O2):
bar():
cmp BYTE PTR fs:guard variable for bar()::_@tpoff, 0
je .L8
ret
.L8:
sub rsp, 8
call foo()
mov BYTE PTR fs:guard variable for bar()::_@tpoff, 1
add rsp, 8
ret
guard variable for bar()::_:
.zero 8
fs
段基址是线程本地存储的地址(至少在 x86-64 Linux 上)。
.zero 8
保留 8 个字节的零(大概在 BSS 中)。查看 GAS 手册:https://sourceware.org/binutils/docs/as/Zero.html, links in https://whosebug.com/tags/x86/info.
@tpoff
大概意思是相对于线程本地存储来解决它,可能代表线程偏移量,我不知道。
它的其余部分看起来类似于 gcc 通常为需要 运行 时间初始化程序的 static
局部变量所做的事情:它每次进入函数时都会检查的保护变量,落空在已经初始化的情况下。
1 字节保护变量在线程本地存储中。实际的 _
本身被优化掉了,因为它从未被读取。 请注意 foo
returns.
之后没有存储 eax
顺便说一句,_
是一个奇怪的(坏的)变量名选择。容易错过,可能留给实现使用。
它在这里有一个很好的优化:通常(对于非线程局部static int var = foo();
)如果它发现守卫变量还没有被初始化,它需要一种线程安全的方式来确保只有一个线程实际上进行初始化(本质上是获取锁)。
但是这里每个线程都有自己的守卫变量(并且应该运行foo()
第一次不管其他线程在做什么)所以它不需要调用 run_once
函数来获得互斥。
(抱歉,我的回答很简短,稍后我可能会用一个关于非线程本地 static
局部变量的 https://godbolt.org/ 的示例来扩展它。或者找到一个关于它的 SO Q&A。)
我只是 运行 跨过这项技术,每个线程 运行 代码一次。我不知道它在最低级别上是如何工作的。特别是,fs
指向什么? .zero 8
是什么意思?标识符是 @tpoff
是有原因的吗?
int foo();
void bar()
{
thread_local static auto _ = foo();
}
输出(带-O2):
bar():
cmp BYTE PTR fs:guard variable for bar()::_@tpoff, 0
je .L8
ret
.L8:
sub rsp, 8
call foo()
mov BYTE PTR fs:guard variable for bar()::_@tpoff, 1
add rsp, 8
ret
guard variable for bar()::_:
.zero 8
fs
段基址是线程本地存储的地址(至少在 x86-64 Linux 上)。
.zero 8
保留 8 个字节的零(大概在 BSS 中)。查看 GAS 手册:https://sourceware.org/binutils/docs/as/Zero.html, links in https://whosebug.com/tags/x86/info.
@tpoff
大概意思是相对于线程本地存储来解决它,可能代表线程偏移量,我不知道。
它的其余部分看起来类似于 gcc 通常为需要 运行 时间初始化程序的 static
局部变量所做的事情:它每次进入函数时都会检查的保护变量,落空在已经初始化的情况下。
1 字节保护变量在线程本地存储中。实际的 _
本身被优化掉了,因为它从未被读取。 请注意 foo
returns.
eax
顺便说一句,_
是一个奇怪的(坏的)变量名选择。容易错过,可能留给实现使用。
它在这里有一个很好的优化:通常(对于非线程局部static int var = foo();
)如果它发现守卫变量还没有被初始化,它需要一种线程安全的方式来确保只有一个线程实际上进行初始化(本质上是获取锁)。
但是这里每个线程都有自己的守卫变量(并且应该运行foo()
第一次不管其他线程在做什么)所以它不需要调用 run_once
函数来获得互斥。
(抱歉,我的回答很简短,稍后我可能会用一个关于非线程本地 static
局部变量的 https://godbolt.org/ 的示例来扩展它。或者找到一个关于它的 SO Q&A。)