[英]What is gcc doing here to run this code once per thread?
I just ran across this technique for running code once per thread. 我刚刚遇到这种技术,每个线程运行一次代码。 I don't know how it works at the lowest level though.
我不知道它是如何在最低级别工作的。 Especially, what's
fs
pointing to? 特别是,
fs
指向什么? What does .zero 8
mean? .zero 8
是什么意思? Is there a reason the identifier is @tpoff
? 标识符是
@tpoff
有原因吗?
int foo();
void bar()
{
thread_local static auto _ = foo();
}
Output (with -O2): 输出(带-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
The fs
segment base is the address of thread-local storage (on x86-64 Linux at least). fs
段基础是线程本地存储的地址(至少在x86-64 Linux上)。
.zero 8
reserves 8 bytes of zeros (presumably in the BSS). .zero 8
保留8个字节的零(可能在BSS中)。 Check the GAS manual: https://sourceware.org/binutils/docs/as/Zero.html , links in https://stackoverflow.com/tags/x86/info . 检查煤气手册: https://sourceware.org/binutils/docs/as/Zero.html ,在链接https://stackoverflow.com/tags/x86/info 。
@tpoff
presumably means to address it relative to thread-local storage, probably stands for thread something offset, I don't know. @tpoff
可能意味着相对于线程本地存储来解决它,可能代表线程偏移的东西,我不知道。
The rest of it looks similar to what gcc normally does for static
local variables that need a runtime initializer: a guard variable that it checks every time it enters the function, falling through in the already-initialized case. 其余部分看起来类似于gcc通常对需要运行时初始化程序的
static
局部变量所执行的操作:每次进入函数时都会检查的保护变量,在已经初始化的情况下会丢失。
The 1-byte guard variable is in thread-local storage. 1字节保护变量位于线程本地存储中。 The actual
_
itself is optimized away because it's never read. 实际
_
本身已被优化掉,因为它从未被读过。 Notice there's no store of eax
after foo
returns. 请注意,
foo
返回后没有存储eax
。
BTW, _
is a weird (bad) choice for a variable name. BTW,
_
是变量名称的一个奇怪(坏)选择。 Easy to miss it, and probably reserved for use by the implementation. 容易错过它,并且可能保留用于实现。
It has a nice optimization here: normally (for non-thread-local static int var = foo();
) if it finds the guard variable isn't already initialized, it needs a thread-safe way to make sure only one thread actually does the initialization (essentially taking a lock). 它在这里有一个很好的优化:通常(对于非线程局部
static int var = foo();
)如果发现保护变量尚未初始化,它需要一种线程安全的方法来确保实际上只有一个线程进行初始化(基本上是锁定)。
But here each thread has its own guard variable (and should run foo()
the first time regardless of what other threads are doing) so it doesn't need to call a run_once
function to get mutual exclusion. 但是这里每个线程都有自己的保护变量(并且应该第一次运行
foo()
而不管其他线程在做什么)所以它不需要调用run_once
函数来实现互斥。
(sorry for the short answer, I may expand this later with an example on https://godbolt.org/ of a non-thread-local static
local variable. Or find an SO Q&A about it.) (对不起,简短的回答,我稍后可以通过https://godbolt.org/上的一个非线程局部
static
局部变量的例子来扩展它。或者找一个关于它的SO Q&A。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.