Assume there is some not-reentrant function that uses global variables:
int i;
void foo(void){
/* modify i */
}
And then, I want to use this function in multithreaded code, so I can change code this way:
void foo(int i){
/* modify i */
}
or, by using gcc __thread specifier, more simplier:
__thread int i;
void foo(void){
/* modify i */
}
Advantages of the last is that I don't need to change another code which call foo().
My questions is, how much overhead of thread-local storage is? Is there some not obvious issues with TLS?
Is there some overhead if I will modify TLS`ed variable via separate pointer, like this:
__thread int i;
void foo(void){
int *p = &i;
/* modify i using p pointer */
}
Thanks.
TLS is always going to be slow relative to simple access. Accessing TLS globals in a tight loop is going to be slow, too. Try caching the TLS value in a temporary instead.
Thread-local storage (TLS) is a mechanism by which variables are allocated such that there is one instance of the variable per extant thread. The run-time model GCC uses to implement this originates in the IA-64 processor-specific ABI, but has since been migrated to other processors as well.
Thread Local Storage (TLS) is the mechanism by which each thread in a given multithreaded process allocates storage for thread-specific data. In standard multithreaded programs, data is shared among all threads of a given process, whereas thread local storage is the mechanism for allocating per-thread data.
With thread local storage (TLS), you can provide unique data for each thread that the process can access using a global index. One thread allocates the index, which can be used by the other threads to retrieve the unique data associated with the index.
And then, I want to use this function in multithreaded code, so I can change code this way:
void foo(int i){
/* modify i */
}
This will certainly not work, as you will only be modifying a copy of i
. You 'd need to pass an int*
or int&
instead if you want the changes to stick.
Using TLS will certainly not cause any significant overhead (either in space or time) over any custom approach you might follow to implement the same functionality. Compilers in practice implement TLS by dynamically allocating a storage "slot" in a global data structure that holds your thread-local variable.
When you access a thread-local variable at runtime, there is an extra level of indirection: first the runtime has to access the appropriate thread-local variable table for the current thread, and then to fetch the value out of the table. This fetching is done using an index into the array (which is an O(1) operation).
If you intend to do this:
__thread int i;
void foo(void){
int *p = &i;
/* modify i using p pointer */
}
then there is no need to access i
using a pointer. Think of i
as a global variable that has a different value for each running thread. You wouldn't need to access a normal global through a pointer to make changes stick, so there's also no need to use a pointer with a thread-local variable.
Finally, thread-local storage is not really meant to store large numbers of variables per thread (there are compiler-dependent limits on the size of the TLS table) but this is something you can easily work around: put many variables into a struct
and make a pointer to the struct
thread-local.
The only problem I see with TLS is its possible limited size. It depends on the system, so you can face porting or scaling problems (BTW, TLS may be not available at all on some systems)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With