24

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.

ks1322
  • 33,961
  • 14
  • 109
  • 164
edA-qa mort-ora-y
  • 30,295
  • 39
  • 137
  • 267
  • 3
    Of course, the general idea is that you cannot. :-) Why not let each thread report its private value using a non-local data structure? – Bo Persson Mar 15 '11 at 09:39
  • presumably `__thread` tells the compiler it can use CPU registers. if so that would make direct access impossible due to hardware constraints. – SpliFF Mar 15 '11 at 09:42
  • 2
    @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 Mar 15 '11 at 10:14
  • @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. – edA-qa mort-ora-y Mar 15 '11 at 10:16
  • @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? – Benny Jun 20 '14 at 06:50
  • 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`. I'll probably have a go at writing something like this soon. – KayEss Dec 21 '14 at 10:01
  • 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. – Michael Chourdakis Dec 30 '20 at 18:55
  • @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 Jan 05 '21 at 11:19

4 Answers4

18

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.

Jon
  • 428,835
  • 81
  • 738
  • 806
  • 6
    This doesn't address my question. – edA-qa mort-ora-y Mar 15 '11 at 10:10
  • 5
    @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. – Jon Mar 15 '11 at 10:55
  • 6
    @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. – Damon Mar 15 '11 at 11:09
  • 3
    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 Mar 15 '11 at 11:18
  • 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 Mar 15 '11 at 12:46
  • 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). – edA-qa mort-ora-y Mar 15 '11 at 12:52
  • 1
    @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. – Jon Mar 15 '11 at 12:52
  • @edA-qa mort-ora-y: Then I 'm afraid that `___tls_get_addr` is your only hope. – Jon Mar 15 '11 at 12:54
5

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;
}
Dima Tisnek
  • 11,241
  • 4
  • 68
  • 120
George Kourtis
  • 2,381
  • 3
  • 18
  • 28
  • 1
    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.] – tower120 Nov 21 '17 at 15:04
3

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

edA-qa mort-ora-y
  • 30,295
  • 39
  • 137
  • 267
3

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.

  • 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. – edA-qa mort-ora-y Jan 05 '21 at 11:21
  • 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. – Zoltan Dewitt Jan 05 '21 at 17:31
  • @edA-qa mort-ora-y :: This answer is very useful for me. Now, I will guess the reason that OP is not satisfied. OP mentioned that we wanted to "track this value at the start of each thread". However, in this answer, the registration to `foos` might not even happen, because it is possible that some threads may never access `tls_foo`. Thread local variables are initialized only when referred to. – cppBeginner Dec 18 '22 at 04:18