Access thread-local from another thread

12,934

Solution 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).

Solution 2

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.

Update:

The GCC documentation on __thread says:

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.

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.

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.

Solution 3

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.

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

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

#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;
}
Share:
12,934

Related videos on Youtube

edA-qa mort-ora-y
Author by

edA-qa mort-ora-y

I'm an experienced programmer who has worked in numerous domains such graphic rendering, telecommunications, scientific applications, business processes, video games, financial platforms, and development products. For more about programming visit Musing Mortoray, or check out my live stream. If you’d like private mentoring check out my profile at Codementor. I’m the creator of the Leaf programming language.

Updated on January 05, 2021

Comments

  • edA-qa mort-ora-y
    edA-qa mort-ora-y over 3 years

    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.

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

    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.


    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 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.

    • Bo Persson
      Bo Persson about 13 years
      Of course, the general idea is that you cannot. :-) Why not let each thread report its private value using a non-local data structure?
    • Mamey
      Mamey about 13 years
      presumably __thread tells the compiler it can use CPU registers. if so that would make direct access impossible due to hardware constraints.
    • edA-qa mort-ora-y
      edA-qa mort-ora-y about 13 years
      @SpliFF, __thread locals are ultimately just locations in normal memory. You may take the address of it and give it to another thread to access.
    • edA-qa mort-ora-y
      edA-qa mort-ora-y about 13 years
      @Bo, that is my comment about lacking a start-thread hook. I do not have the possibility to intercept all thread creation and register the variable. Similarly I can't have the overhead of a function call for any read-access to the variable from the owning thread.
    • Benny
      Benny almost 10 years
      @edA-qamort-ora-y I also wanted to ask a very similar question, but for the Windows implementation of thread local storage. Did you by any chance find the answer/solution to your question?
    • KayEss
      KayEss over 9 years
      This smells like something that can be implemented in a library. The type of the thread_local is a wrapper around what you actually want so constructor and destructor can register/de-register the thread memory address of the value. I.e. instead of doing thread_local int you do something along the lines of thread_local thread_registration<int>. I'll probably have a go at writing something like this soon.
    • Michael Chourdakis
      Michael Chourdakis over 3 years
      It wouldn't be technically possible as well. In Windows for example, it most likely uses TLS Thread Storage which is not accessible from another thread at the OS level.
    • edA-qa mort-ora-y
      edA-qa mort-ora-y over 3 years
      @MichaelChourdakis See my note about "Thead Local is not private". Maybe Windows has a special model, but that could not be what is used for C++ thread local variables, since those must be public memory.
  • edA-qa mort-ora-y
    edA-qa mort-ora-y about 13 years
    This doesn't address my question.
  • Waihon Yew
    Waihon Yew about 13 years
    @edA-qa mort-ora-y: The question as I understand it reads as "how can I use a hammer to dig a hole?". That's why I suggest using a more appropriate tool for the job.
  • Damon
    Damon about 13 years
    @edA-qa mort-ora-y: That answer addresses your question perfectly, in my opinion. TLS by definition means "I don't want to share this between my threads", and it takes the compiler extra work to ensure that property. The advice to just use a normal global instead of trying to hack around TLS makes sense. Otherwise, it's like putting salt into your coffee and then pouring it down the sink, because you don't like salt in your coffee.
  • edA-qa mort-ora-y
    edA-qa mort-ora-y about 13 years
    TLS may be shared between threads: it is addressable memory like any other. I'm looking for a way to discover those variable addresses without having the source thread communicate them.
  • edA-qa mort-ora-y
    edA-qa mort-ora-y about 13 years
    Yes, I presume I need the pointer of the variable, but I have no thread start hook. I cannot call a registration function. I need Thread B to just be able to lookup the variable in Thread A. It may not be possible; but that is why I'm asking.
  • edA-qa mort-ora-y
    edA-qa mort-ora-y about 13 years
    A global array requires a registration function, but I do not control thread startup. There is no way to force these threads to call an init function (if there is a way to do this then yes, that'd be fine).
  • Waihon Yew
    Waihon Yew about 13 years
    @edA-qa mort-ora-y: I am aware of the fact that thread-local means "multiple copies of this variable", and also of the fact that in principle there should be nothing preventing you from "publicizing" a variable. I have updated the answer to explicitly make that clear; I still believe you are trying to swim against the current.
  • Waihon Yew
    Waihon Yew about 13 years
    @edA-qa mort-ora-y: Then I 'm afraid that ___tls_get_addr is your only hope.
  • tower120
    tower120 over 6 years
    Alas ... tooo unportable. [what if gcc's std::thread will stop using pthreads as native_handle? Or structure changes? This can happen with any next gcc update.]
  • edA-qa mort-ora-y
    edA-qa mort-ora-y over 3 years
    The answer, which I gave, is that it is does not appear possible to do what I've requested. There are many ways to do other things, but the strict requirements of the question do not appear they can be met.
  • Zoltan Dewitt
    Zoltan Dewitt over 3 years
    I guess I don't understand why this doesn't satisfy your requirements. You don't need to know the thread entry points, simply define a struct that will register a pointer to itself on construction, and then make that struct your __thread variable. There is not going to be any overhead for doing this beyond the initial registration at thread startup.