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

edA*_*a-y 18 c++ linux multithreading gcc thread-local-storage

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

该变量__thread在GCC中声明.目标平台是Linux,但独立性可能不错(但GCC具体可行).

缺少线程启动挂钩,我无法在每个线程的开头简单地跟踪此值.需要以这种方式跟踪所有线程(不仅仅是特别启动的线程).

像boost boost_local_storage或使用pthread键的更高级别的包装器不是一个选项.我要求使用真正的__thread局部变量.


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


线程本地不是私有的:另一个关于线程局部变量的误解.这些线程绝不是某种私有变量.它们是全局可寻址的内存,其限制是它们的生命周期与线程相关联.任何线程中的任何函数,如果给出指向这些变量的指针,都可以修改它们.上面的问题主要是关于如何获得指针地址.

Jon*_*Jon 15

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

重要说明!

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

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

更新:

GCC文档__thread说:

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

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

如果你真的喜欢冒险,你可以尝试挖掘信息___tls_get_addr(从这个由上述GCC文档链接的PDF开始).但是这种方法具有如此高度的编译器和平台特性,因此缺乏文档,它应该导致警报在任何人的头脑中消失.

  • 这不能解决我的问题. (4认同)
  • @ edA-qa mort-ora-y:我理解的问题是"我怎么能用锤子挖洞?".这就是我建议使用更合适的工具的原因. (4认同)
  • @ edA-qa mort-ora-y:在我看来,这个答案完美地解决了你的问题.根据定义,TLS意味着"我不想在我的线程之间共享",并且需要编译器额外的工作来确保该属性.建议只使用普通的全局而不是试图破解TLS是有道理的.否则,就像把盐放入咖啡中,然后将其倒入水槽,因为你不喜欢咖啡中的盐. (4认同)
  • TLS 可以在线程之间共享:它像任何其他内存一样是可寻址的内存。我正在寻找一种方法来发现这些变量地址,而无需源线程与它们通信。 (3认同)

Geo*_*tis 5

我正在寻找同样的东西。我发现在以各种方式搜索网络后没有人回答你的问题,我得到了后续信息:假设在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;
}
Run Code Online (Sandbox Code Playgroud)


edA*_*a-y 2

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

如果没有某种线程初始化挂钩,似乎就没有办法获取该指针(缺少依赖于平台的 ASM 黑客)。