繁体   English   中英

从另一个线程访问线程本地

[英]Access thread-local from another thread

如何从另一个线程读/写线程局部变量? 也就是说,在线程 AI 中想要访问线程 B 的线程本地存储区中的变量。 我知道另一个线程的 ID。

该变量在 GCC 中声明为__thread 目标平台是 Linux,但独立性可能很好(不过 GCC 特定是可以的)。

缺少线程启动钩子,我无法在每个线程开始时简单地跟踪这个值。 所有线程都需要以这种方式进行跟踪(不仅仅是特别启动的线程)。

更高级别的包装器(如 boost thread_local_storage 或使用 pthread 键)不是一种选择。 我需要使用真正的__thread局部变量的性能。


第一个答案是错误的:不能将全局变量用于我想做的事情。 每个线程都必须有自己的变量副本。 此外,出于性能原因,这些变量必须是__thread变量(同样有效的解决方案也可以,但我不知道)。 我也不控制线程入口点,因此这些线程不可能注册任何类型的结构。


线程局部不是私有的:关于线程局部变量的另一个误解。 这些绝不是线程的某种私有变量。 它们是全局可寻址内存,其生命周期与线程相关。 来自任何线程的任何函数,如果给定一个指向这些变量的指针,都可以修改它们。 上面的问题本质上是关于如何获取该指针地址。

如果您想要不是线程局部的线程局部变量,为什么不使用全局变量呢?

重要说明!

我并不是建议您使用单个全局变量来替换线程局部变量。 我建议使用单个全局数组或其他合适的值集合来替换一个线程局部变量。

当然,您必须提供同步,但由于您想将在线程 A 中修改的值公开给线程 B,因此无法解决这个问题。

更新:

__threadGCC 文档说:

当 address-of 运算符应用于线程局部变量时,它会在运行时评估并返回该变量的当前线程实例的地址。 任何线程都可以使用如此获得的地址。 当线程终止时,该线程中指向线程局部变量的任何指针都将变为无效。

因此,如果您坚持采用这种方式,我想可以在线程产生之后从它所属的线程中获取线程局部变量的地址。 然后,您可以将指向该内存位置的指针存储到映射(线程 ID => 指针),并让其他线程以这种方式访问​​该变量。 这假设您拥有衍生线程的代码。

如果你真的很喜欢冒险,你可以尝试在___tls_get_addr上挖掘信息(从这个 PDF开始,该 PDF链接到上述 GCC 文档)。 但是这种方法是高度编译器和平台特定的,并且缺乏文档,它应该引起任何人的注意。

我正在寻找同样的东西。 正如我看到的,在以各种方式搜索网络后,没有人回答您的问题,我得到了后续信息:假设在 linux (ubuntu) 上为 gcc 编译并使用 -m64,段寄存器 gs 的值为 0。隐藏部分段的(保存线性地址)指向线程特定的局部区域。 该区域包含该地址的地址(64 位)。 在较低的地址存储所有线程局部变量。 该地址是native_handle() 因此,为了访问线程本地数据,您应该通过该指针进行操作。

换句话说: (char*)&variable-(char*)myThread.native_handle()+(char*)theOtherThread.native_handle()

演示上述假设 g++,linux,pthreads 的代码是:

#include <iostream>
#include <thread>
#include <sstream>

thread_local int B=0x11111111,A=0x22222222;

bool shouldContinue=false;

void code(){
    while(!shouldContinue);
    std::stringstream ss;
    ss<<" A:"<<A<<" B:"<<B<<std::endl;
    std::cout<<ss.str();
}

//#define ot(th,variable) 
//(*( (char*)&variable-(char*)(pthread_self())+(char*)(th.native_handle()) ))

int& ot(std::thread& th,int& v){
    auto p=pthread_self();
    intptr_t d=(intptr_t)&v-(intptr_t)p;
    return *(int*)((char*)th.native_handle()+d);
}

int main(int argc, char **argv)
{       

        std::thread th1(code),th2(code),th3(code),th4(code);

        ot(th1,A)=100;ot(th1,B)=110;
        ot(th2,A)=200;ot(th2,B)=210;
        ot(th3,A)=300;ot(th3,B)=310;
        ot(th4,A)=400;ot(th4,B)=410;

        shouldContinue=true;

        th1.join();
        th2.join();
        th3.join();
        th4.join();

    return 0;
}

不幸的是,我永远无法找到一种方法来做到这一点。

没有某种线程初始化钩子,似乎没有办法获得该指针(缺少依赖于平台的 ASM hack)。

这是一个老问题,但既然没有给出答案,为什么不使用一个有自己静态注册的类呢?

#include <mutex>
#include <thread>
#include <unordered_map>

struct foo;

static std::unordered_map<std::thread::id, foo*> foos;
static std::mutex foos_mutex;

struct foo
{
    foo()
    {
        std::lock_guard<std::mutex> lk(foos_mutex);
        foos[std::this_thread::get_id()] = this;
    }
};

static thread_local foo tls_foo;

当然,您需要在线程之间进行某种同步以确保线程已注册指针,但是您可以从任何您知道线程 ID 的线程的映射中获取它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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