c++ - gcc 在这里做什么来让每个线程运行一次这段代码?

标签 c++ multithreading gcc assembly thread-local-storage

我刚刚遇到了这种为每个线程运行一次代码的技术。我不知道它在最低级别上是如何工作的。特别是,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 , 链接在 https://stackoverflow.com/tags/x86/info .

@tpoff 大概是指相对于线程本地存储来解决它,可能代表线程偏移量,我不知道。


它的其余部分看起来类似于 gcc 通常为需要运行时初始化程序的 static 局部变量所做的事情:一个每次进入函数时都会检查的保护变量,在已经-初始化案例。

1 字节的保护变量在线程本地存储中。实际的 _ 本身被优化掉了,因为它从未被读取。请注意,在 foo 返回后没有存储 eax

顺便说一句,_ 是一个奇怪的(错误的)变量名选择。很容易错过它,并且可能保留供实现使用。


它在这里有一个很好的优化:通常(对于非线程本地 static int var = foo();)如果它发现 guard 变量还没有被初始化,它需要一个线程- 确保只有一个线程实际执行初始化(本质上是获取锁)的安全方法。

但是这里每个线程都有自己的保护变量(而且应该第一次运行foo(),不管其他线程在做什么)所以它不需要调用 run_once 函数来实现互斥。

(抱歉,我的回答很简短,稍后我可能会在 https://godbolt.org/ 上用一个非线程本地 static 局部变量的示例来扩展它。或者找到一个关于它的 SO Q&A。)

关于c++ - gcc 在这里做什么来让每个线程运行一次这段代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54270228/

相关文章:

java - 为什么这些线程不按顺序运行?

c# - Wait Handles 是否释放线程获取的锁?

c++ - 在 callgrind 输出中解释 _dl_runtime_resolve_xsave'2

c++ - 循环依赖问题

c++ - 对 POSIX 共享内存对象执行基于文件(基于 fd)的访问是否安全?

c++ - 在一行中将 int 写入 std::ofstream::write()

c# - 创建大量任务/线程并等待它们全部完成

c# - 使用 SWIG 从 C++ 初始化对 C# 共享指针的引用

python - MySQL-python,错误: command 'gcc-4.2' failed with exit status 1

c - 为什么 GCC 在使用三字母时发出警告,而在使用二字母时却不发出警告?