简体   繁体   English

什么是gcc在这里每个线程运行一次这个代码?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM