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

时间:2022-12-17 21:01:44

How can I read/write a thread local variable from another thread? That is, in Thread A I would like to access the variable in Thread B's thread local storage area. I know the ID of the other thread.

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

The variable is declared as __thread in GCC. Target platform is Linux, but independence might be nice (GCC specific is okay however).

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

Lacking a thread-start hook there is no way I can simply track this value at the start of each thread. All threads need to be tracked this way (not just specially started ones).

如果没有线程启动钩子,就不可能在每个线程的开头跟踪这个值。所有线程都需要以这种方式进行跟踪(而不仅仅是特殊启动的线程)。

A higher level wrapper like boost thread_local_storage or using pthread keys is not an option. I require the performance of using a true __thread local variable.

像boost thread_local_storage或使用pthread密钥这样的高级包装器不是一个选项。我要求使用真正的__thread局部变量的性能。


FIRST ANSWER IS WRONG: One cannot use global variables for what I want to do. Each thread must have its own copy of the variable. Furthermore, those variables must be __thread variables for performance reasons (an equally efficient solution would also be okay, but I know of none). I also don't control the thread entry points, thus there is no possibility for those threads to register any kind of structure.

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


Thread Local is not private: Another misunderstanding about thread-local variables. These are in no way some kind of private variable for the thread. They are globally addressable memory, with the restriction that their lifetime is tied to the thread. Any function, from any thread, if given a pointer to these variables can modify them. The question above is essentially about how to get that pointer address.

线程本地不是私有的:另一个关于线程本地变量的误解。这些绝不是线程的某种私有变量。它们是全局寻址的内存,其生存期受线程绑定的限制。任何线程的任何函数,如果给定一个指向这些变量的指针,都可以修改它们。上面的问题实际上是关于如何获取这个指针地址。

3 个解决方案

#1


15  

If you want thread local variables that are not thread local, why don't you use global variables instead?

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

Important clarification!

重要的澄清!

I am not suggesting that you use a single global to replace a thread-local variable. I 'm suggesting of using a single global array or other suitable collection of values to replace one thread-local variable.

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

You will have to provide synchronization of course, but since you want to expose a value modified in thread A to thread B there's no getting around that.

当然,您必须提供同步,但是由于您希望将线程a中修改过的值公开给线程B,因此无法回避这一点。

Update:

更新:

The GCC documentation on __thread says:

__thread上的GCC文档说:

When the address-of operator is applied to a thread-local variable, it is evaluated at run-time and returns the address of the current thread's instance of that variable. An address so obtained may be used by any thread. When a thread terminates, any pointers to thread-local variables in that thread become invalid.

当address-of操作符应用于线程本地变量时,在运行时对其进行评估,并返回该变量的当前线程实例的地址。这样获得的地址可以被任何线程使用。当一个线程终止时,任何指向线程本地变量的指针都将失效。

Therefore, if you insist on going this way I imagine it's possible to get the address of a thread local variable from the thread it belongs to, just after the thread is spawned. You could then store a pointer to that memory location to a map (thread id => pointer), and let other threads access the variable this way. This assumes that you own the code for the spawned thread.

因此,如果您坚持这样做,我认为可以从线程所属的线程中获取线程局部变量的地址,就在线程生成之后。然后,您可以存储指向映射的内存位置的指针(线程id =>指针),并让其他线程以这种方式访问该变量。这假设您拥有派生线程的代码。

If you are really adventurous, you could try digging up information on ___tls_get_addr (start from this PDF which is linked to by the aforementioned GCC docs). But this approach is so highly compiler and platform specific and so lacking in documentation that it should be causing alarms to go off in anyone's head.

如果您非常喜欢冒险,可以尝试在___tls_get_addr上挖掘信息(从前面提到的GCC文档链接的这个PDF开始)。但是这种方法是高度编译和平台的,所以缺乏文档,所以它应该引起任何人的警觉。

#2


2  

I am searching for the same thing. As I see nobody has answered your question after having searched the web in all ways I arrived to the subsequent information: supposing to compile for gcc on linux (ubuntu) and using -m64, the segment register gs holds the value 0. The hidden part of the segment (holding the linear address) points to the thread specific local area. That area contains at that address the address of that address ( 64 bits ). At lower addresses are stored all thread local variables. That address is the native_handle(). So in order to access a threads local data you should do it via that pointer.

我在寻找同样的东西。我在网上搜索了所有相关信息之后,发现没有人回答过您的问题:假设在linux (ubuntu)上编译gcc并使用-m64,段寄存器gs保存值为0。段的隐藏部分(包含线性地址)指向线程特定的局部区域。该区域包含该地址的地址(64位)。在较低的地址存储所有线程本地变量。该地址是native_handle()。因此,为了访问线程本地数据,您应该通过该指针来执行它。

In other words: (char*)&variable-(char*)myThread.native_handle()+(char*)theOtherThread.native_handle()

换句话说:(char *)变量-(char *)myThread.native_handle()+(char *)theOtherThread.native_handle()

The code that demonstrates the above supposing g++,linux,pthreads is:

假设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;
}

#3


1  

I was unfortunately never able to find a way to do this.

不幸的是,我一直找不到这样做的方法。

Without some kind of thread init hook there just doesn't appear to be a way to get at that pointer (short of ASM hacks that would be platform dependent).

如果没有某种类型的线程init钩子,就不可能找到获得该指针的方法(除了依赖于平台的ASM hacks)。

#1


15  

If you want thread local variables that are not thread local, why don't you use global variables instead?

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

Important clarification!

重要的澄清!

I am not suggesting that you use a single global to replace a thread-local variable. I 'm suggesting of using a single global array or other suitable collection of values to replace one thread-local variable.

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

You will have to provide synchronization of course, but since you want to expose a value modified in thread A to thread B there's no getting around that.

当然,您必须提供同步,但是由于您希望将线程a中修改过的值公开给线程B,因此无法回避这一点。

Update:

更新:

The GCC documentation on __thread says:

__thread上的GCC文档说:

When the address-of operator is applied to a thread-local variable, it is evaluated at run-time and returns the address of the current thread's instance of that variable. An address so obtained may be used by any thread. When a thread terminates, any pointers to thread-local variables in that thread become invalid.

当address-of操作符应用于线程本地变量时,在运行时对其进行评估,并返回该变量的当前线程实例的地址。这样获得的地址可以被任何线程使用。当一个线程终止时,任何指向线程本地变量的指针都将失效。

Therefore, if you insist on going this way I imagine it's possible to get the address of a thread local variable from the thread it belongs to, just after the thread is spawned. You could then store a pointer to that memory location to a map (thread id => pointer), and let other threads access the variable this way. This assumes that you own the code for the spawned thread.

因此,如果您坚持这样做,我认为可以从线程所属的线程中获取线程局部变量的地址,就在线程生成之后。然后,您可以存储指向映射的内存位置的指针(线程id =>指针),并让其他线程以这种方式访问该变量。这假设您拥有派生线程的代码。

If you are really adventurous, you could try digging up information on ___tls_get_addr (start from this PDF which is linked to by the aforementioned GCC docs). But this approach is so highly compiler and platform specific and so lacking in documentation that it should be causing alarms to go off in anyone's head.

如果您非常喜欢冒险,可以尝试在___tls_get_addr上挖掘信息(从前面提到的GCC文档链接的这个PDF开始)。但是这种方法是高度编译和平台的,所以缺乏文档,所以它应该引起任何人的警觉。

#2


2  

I am searching for the same thing. As I see nobody has answered your question after having searched the web in all ways I arrived to the subsequent information: supposing to compile for gcc on linux (ubuntu) and using -m64, the segment register gs holds the value 0. The hidden part of the segment (holding the linear address) points to the thread specific local area. That area contains at that address the address of that address ( 64 bits ). At lower addresses are stored all thread local variables. That address is the native_handle(). So in order to access a threads local data you should do it via that pointer.

我在寻找同样的东西。我在网上搜索了所有相关信息之后,发现没有人回答过您的问题:假设在linux (ubuntu)上编译gcc并使用-m64,段寄存器gs保存值为0。段的隐藏部分(包含线性地址)指向线程特定的局部区域。该区域包含该地址的地址(64位)。在较低的地址存储所有线程本地变量。该地址是native_handle()。因此,为了访问线程本地数据,您应该通过该指针来执行它。

In other words: (char*)&variable-(char*)myThread.native_handle()+(char*)theOtherThread.native_handle()

换句话说:(char *)变量-(char *)myThread.native_handle()+(char *)theOtherThread.native_handle()

The code that demonstrates the above supposing g++,linux,pthreads is:

假设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;
}

#3


1  

I was unfortunately never able to find a way to do this.

不幸的是,我一直找不到这样做的方法。

Without some kind of thread init hook there just doesn't appear to be a way to get at that pointer (short of ASM hacks that would be platform dependent).

如果没有某种类型的线程init钩子,就不可能找到获得该指针的方法(除了依赖于平台的ASM hacks)。