标签: thread-local-storage

是否有可能多个动态链接库(DLL)从静态库(LIB)共享线程本地存储

我有一个由许多DLL文件组成的游戏.其中一些DLL链接到相同的静态库(LIB).

所以像这样:

Game.exe -> Root.dll -> Child.dll
               |            |
               |            '-> Common.lib (contains __declspec(thread))
               |
               '-> Common.lib (contains __declspec(thread))
Run Code Online (Sandbox Code Playgroud)

Root.dll加载静态链接Common.lib的Child.dll.Root还静态链接Common.lib.因为Common是静态链接的,所以它会直接编译到加载dll中(例如Root和Child).

Common.lib包含使用线程本地存储(TLS)的变量.

__declspec(thread) static void* s_threadValues[PlatformThreadSlotsMax];
Run Code Online (Sandbox Code Playgroud)

这会导致一些有问题的行为:Root.dll和Child.dll每个都包含一个不同的TLS数据实例(s_threadValues).即使在同一个线程上,如果Root.dll调用Common.lib中定义的函数,如果从Child.dll调用相同的函数,则s_threadValues的值将与其值不同.

由于两个DLL都是从同一个线程访问这个TLS,我希望共享TLS,但事实并非如此.

现在,如果我将Common.lib更改为动态链接(例如Common.dll),则不会出现此问题:对于Root.dll和Child.dll,s_threadValues是相同的.

这是预期的行为吗?无论如何在动态库之间共享静态库中定义的TLS共享使用它吗?

c++ dll multithreading static-libraries thread-local-storage

6
推荐指数
1
解决办法
2148
查看次数

nodejs域如何在多个请求的幕后实际工作?

我的用例要求node.js域在请求级别跨服务器文件共享信息.

express.js中的示例实现

domain = require('domain');

app.use(function(req, res, next) {
    var reqDomain = domain.create();
    reqDomain.add(req);
    reqDomain.add(res);
    reqDomain.run(next);
});
Run Code Online (Sandbox Code Playgroud)

Nodejs域显式绑定的更多解释

controller/service中 - process.domain将为您提供上面创建的域并且您可以轻松地将值绑定到此域.例如:

process.domain.obj = {};
Run Code Online (Sandbox Code Playgroud)

这种解释足以理解域的用法.

问题

  1. 将域用于多个请求是否安全?

  2. 如何确保process.domain对于不同的请求是不同的而不是相同的?

我还想知道在继续本地存储中如何处理这些问题

javascript node.js thread-local-storage express node.js-domains

6
推荐指数
1
解决办法
423
查看次数

如何减少或消除__tls_init调用?

我正在使用依赖的第三方库thread_local.这导致我的程序__tls_init()重复调用,即使在某些周期的每次迭代中(我还没有检查所有这些),尽管thread_local变量已经被同一函数中早期的另一个调用无条件地初始化(事实上,在接近开始时)整个节目).

__tls_init()我的第一个指示x86_64

cmpb    $0, %fs:__tls_guard@tpoff
je      .L530
ret
.L530:
pushq   %rbp
pushq   %rbx
subq    (some stack space), %rsp
movb    $1, %fs:__tls_guard@tpoff
Run Code Online (Sandbox Code Playgroud)

所以第一次按每个线程调用它时,值at %fs:__tls_guard@tpoff设置为,1并且进一步调用立即返回.但是,这意味着call每次thread_local访问变量时都会产生所有开销,对吧?

请注意,这是一个静态链接(实际上是生成!)函数,因此编译器"知道"它从这个条件开始,并且完全可以想象流分析发现不必多次调用此函数.但事实并非如此.

是否有可能摆脱多余的call __tls_init指令,或者至少阻止编译器在时间关键的部分发出它们?

实际编译的示例情况:( - O3)

pushq   %r13
movq    %rdi, %r13
pushq   %r12
pushq   %rbp
pushq   %rbx
movq    %rsi, %rbx
subq    $88, %rsp
call    __tls_init              // always gets called
movq    (%rbx), %rdi
call    <some local function>
movq    8(%rax), %r12 …
Run Code Online (Sandbox Code Playgroud)

optimization g++ internal thread-local-storage

6
推荐指数
1
解决办法
301
查看次数

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

我刚刚遇到这种技术,每个线程运行一次代码.我不知道它是如何在最低级别工作的.特别是,fs指向什么?什么.zero 8意思?标识符是否有原因@tpoff

int foo();

void bar()
{
    thread_local static auto _ = foo();
}
Run Code Online (Sandbox Code Playgroud)

输出(带-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
Run Code Online (Sandbox Code Playgroud)

c++ assembly multithreading gcc thread-local-storage

6
推荐指数
1
解决办法
209
查看次数

在非boost程序中使用boost :: thread_specific_ptr

我正在阅读文档部分boost::thread_specific_ptr,并尝试解析此段落:

注意:在某些平台上,不会对使用平台的本机API创建的线程执行特定于线程的数据的清理.在这些平台上,只有使用boost :: thread启动的线程才会进行此类清理,除非从该线程手动调用boost :: on_thread_exit().

首先,这可能是一个迂腐的观点:我认为他们的意思是说boost::this_thread::at_thread_exit()而不是boost::on_thread_exit().否则我真的迷路了.

更重要的是,线程究竟需要做什么?它是否足以将一些无操作函数传递给at_thread_exit(),还是需要传递其他东西?

(这个主题在这里的评论中讨论过,但我仍然不确定我需要做什么.)

(背景故事:我正在寻找解决我今天早些时候提出的问题的方法).

c++ multithreading boost boost-thread thread-local-storage

5
推荐指数
1
解决办法
2837
查看次数

在流行的现代操作系统中,线程本地存储是否有已知的大小限制?

当我使用thread_local, _Thread_local, __thread, or 时__declspec(thread),编译器似乎在创建线程时分配一个线程本地存储,并将地址存储在 x86 派生系统中的fsorgs寄存器中。

在这种情况下,是否有“线程本地存储溢出”之类的东西?

c c++ multithreading thread-local-storage

5
推荐指数
1
解决办法
2199
查看次数

使用 thread_local 存储的每线程单例

这种thread_local存储持续时间的用法是否有任何警告:

template <class T>
inline T &thread_local_get()
{
  thread_local T t;
  return t;
}
Run Code Online (Sandbox Code Playgroud)

然后在不同的线程中(例如)

thread_local_get<float>() += 1.f;
Run Code Online (Sandbox Code Playgroud)

cppreference 上的文档说明了线程本地存储持续时间:

线程存储持续时间。对象在线程开始时分配,在线程结束时释放。每个线程都有自己的对象实例。只有声明为 thread_local 的对象具有此存储持续时间。thread_local 可以与 static 或 extern 一起出现以调整链接。

这是否thread_local为每个 T(编译期间)和每个调用线程正确分配了一个实例?是否有任何情况会导致例如未定义的行为?

c++ singleton thread-local thread-local-storage c++11

5
推荐指数
1
解决办法
1404
查看次数

Clang 目标:不支持线程本地存储

关于编译器选项有几个问题。现在我使用以下内容:

-target i386-windows-gnu -mno-sse -c -O3
-target x86_64-windows-gnu -mcx16 -c -O3
-target i386-linux-gnu -mno-sse -c -O3
-target x86_64-linux-gnu -mcx16 -c -O3
-target i386-darwin-gnu -mno-sse -fomit-frame-pointer -c -O3
-target x86_64-macos-gnu -fomit-frame-pointer -c -O3
-target armv7-none-linux-androideabi -mfpu=neon -mfloat-abi=hard -mthumb -fPIC -c -O3
-target aarch64-linux-android -c -O3
-target armv7m-none-ios-gnueabi -mfpu=neon -mfloat-abi=hard -mthumb -c -O3
-target arm64-darwin-gnu -fno-stack-protector -c -O3
Run Code Online (Sandbox Code Playgroud)

仅在 Linux/Android 上没有投诉。对于其他平台,它会发出警告(https://godbolt.org/z/YhZ5uc):

clang-9: warning: argument unused during compilation: '--gcc-toolchain=/opt/compiler-explorer/gcc-9.2.0' [-Wunused-command-line-argument]
Compiler returned: 0
Run Code Online (Sandbox Code Playgroud)

ARM32平台不支持preserve_most属性(https://godbolt.org/z/SQRJB2):

<source>:2:21: warning: 'preserve_most' calling convention …
Run Code Online (Sandbox Code Playgroud)

macos multithreading clang compiler-options thread-local-storage

5
推荐指数
0
解决办法
1619
查看次数

底层段寄存器的线程本地实际使用

我阅读了许多文章和 S/O 答案说(在 linux x86_64 上)FS(或某些变体中的 GS)引用了一个特定于线程的页表条目,然后它给出了一个指向可共享的实际数据的指针数组数据。当线程被交换时,所有的寄存器都被切换,因此线程基页会发生变化。线程变量通过名称访问,只需要 1 个额外的指针跃点,并且引用的值可以共享给其他线程。一切都好,说得通。

事实上,如果你查看__errno_location(void)背后的函数的代码errno,你会发现类似的东西(这是来自 musl,但 gnu 并没有太大的不同):

static inline struct pthread *__pthread_self()
{
    struct pthread *self;
    __asm__ __volatile__ ("mov %%fs:0,%0" : "=r" (self) );
    return self;
}
Run Code Online (Sandbox Code Playgroud)

来自 glibc:

=> 0x7ffff6efb4c0 <__errno_location>:   endbr64
   0x7ffff6efb4c4 <__errno_location+4>: mov    0x6add(%rip),%rax        # 0x7ffff6f01fa8
   0x7ffff6efb4cb <__errno_location+11>:        add    %fs:0x0,%rax
   0x7ffff6efb4d4 <__errno_location+20>:        retq
Run Code Online (Sandbox Code Playgroud)

所以我的期望是 FS 的实际值会因每个线程而改变。例如,在调试器下, gdb: info regor p $fs,我会看到 FS 的值在不同的线程中是不同的,但没有: ds, es, fs, gs 一直都为零。

在我自己的代码中,我写了类似下面的内容并得到相同的结果 - FS 没有改变,但 TLV “有效”:

struct …
Run Code Online (Sandbox Code Playgroud)

c++ linux x86-64 thread-local-storage memory-segmentation

5
推荐指数
1
解决办法
149
查看次数

为什么 gcc 不消除对 `_tls_get_addr()` 的连续调用?

我有使用 thread_local 缓冲区的代码,类似于:

int func() {
    thread_local std::vector<int> buffer;

    buffer.resize(0);
    for (int i = 0; i < 10000; i++) {
        buffer.push_back(i);
    }

    return processing(buffer);
}
Run Code Online (Sandbox Code Playgroud)

在分析我的代码时,我注意到 gcc 在循环体内调用了一个调用_tls_get_addr(),以便访问buffer. 循环体的Godbolt反汇编如下所示:

        lea     rbx, -20[rbp]
        data16  lea rdi, f()::buffer@tlsgd[rip]
        .value  0x6666
        rex64
        call    __tls_get_addr@PLT  ; <- This call!
        mov     rsi, rbx
        mov     rdi, rax
        call    std::vector<int, std::allocator<int> >::push_back(int const&)@PLT
Run Code Online (Sandbox Code Playgroud)

这些调用大大减慢了循环速度。我可以手动使用此版本并参考:

        lea     rbx, -20[rbp]
        data16  lea rdi, f()::buffer@tlsgd[rip]
        .value  0x6666
        rex64
        call    __tls_get_addr@PLT  ; <- This call!
        mov …
Run Code Online (Sandbox Code Playgroud)

c++ multithreading gcc thread-local-storage

5
推荐指数
0
解决办法
439
查看次数