简体   繁体   English

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

[英]Access thread-local from another thread

How can I read/write a thread local variable from another thread?如何从另一个线程读/写线程局部变量? That is, in Thread AI would like to access the variable in Thread B's thread local storage area.也就是说,在线程 AI 中想要访问线程 B 的线程本地存储区中的变量。 I know the ID of the other thread.我知道另一个线程的 ID。

The variable is declared as __thread in GCC.该变量在 GCC 中声明为__thread Target platform is Linux, but independence might be nice (GCC specific is okay however).目标平台是 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.更高级别的包装器(如 boost thread_local_storage 或使用 pthread 键)不是一种选择。 I require the performance of using a true __thread local variable.我需要使用真正的__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).此外,出于性能原因,这些变量必须是__thread变量(同样有效的解决方案也可以,但我不知道)。 I also don't control the thread entry points, thus there is no possibility for those threads to register any kind of structure.我也不控制线程入口点,因此这些线程不可能注册任何类型的结构。


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.上面的问题本质上是关于如何获取该指针地址。

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: __threadGCC 文档说:

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.当 address-of 运算符应用于线程局部变量时,它会在运行时评估并返回该变量的当前线程实例的地址。 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.当线程终止时,该线程中指向线程局部变量的任何指针都将变为无效。

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.然后,您可以将指向该内存位置的指针存储到映射(线程 ID => 指针),并让其他线程以这种方式访问​​该变量。 This assumes that you own the code for the spawned thread.这假设您拥有衍生线程的代码。

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

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.正如我看到的,在以各种方式搜索网络后,没有人回答您的问题,我得到了后续信息:假设在 linux (ubuntu) 上为 gcc 编译并使用 -m64,段寄存器 gs 的值为 0。隐藏部分段的(保存线性地址)指向线程特定的局部区域。 That area contains at that address the address of that address ( 64 bits ).该区域包含该地址的地址(64 位)。 At lower addresses are stored all thread local variables.在较低的地址存储所有线程局部变量。 That address is the native_handle() .该地址是native_handle() So in order to access a threads local data you should do it via that pointer.因此,为了访问线程本地数据,您应该通过该指针进行操作。

In other words: (char*)&variable-(char*)myThread.native_handle()+(char*)theOtherThread.native_handle()换句话说: (char*)&variable-(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;
}

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).没有某种线程初始化钩子,似乎没有办法获得该指针(缺少依赖于平台的 ASM hack)。

This is an old question, but since there is no answer given, why not use a class that has its own static registration?这是一个老问题,但既然没有给出答案,为什么不使用一个有自己静态注册的类呢?

#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;

Of course you would need some kind of synchronization between the threads to ensure that the thread had registered the pointer, but you can then grab it from the map from any thread where you know the thread's id.当然,您需要在线程之间进行某种同步以确保线程已注册指针,但是您可以从任何您知道线程 ID 的线程的映射中获取它。

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

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