Linux Thread Local Storage
by Wenwei Weng
Thread-local storage (TLS) is a mechanism by which variables are allocated such that there is one instance of the variable per extant thread.
There are two ways to use TLS.
#Use the keyword “_thread” provided by compiler
In the following example, “_thread” keyword which is supported by gcc compiler to tell the two integer variables “TLS_data1” and TLS_data2” are TLS varaibles.
#define _MULTI_THREADED
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void foo(void); /* Functions that use the TLS data */
void bar(void);
#define checkResults(string, val) { \
if (val) { \
printf("Failed with %d at %s", val, string); \
exit(1); \
} \
}
/*
Use the keyword provided by pthread.h to delcare the following variable
is thread specific, i.e. it is only visible to a specific thread,
not shared/common to all thread.
These variables are stored in thread local storage (TLS) area.
*/
__thread int TLS_data1;
__thread int TLS_data2;
#define NUMTHREADS 2
typedef struct {
int data1;
int data2;
} threadparm_t;
void *thread_run(void *parm)
{
int rc;
threadparm_t *gData;
printf("Thread %.16llx: Entered\n", pthread_self());
gData = (threadparm_t *)parm;
/* Assign the value from global variable to thread specific variable*/
TLS_data1 = gData->data1;
TLS_data2 = gData->data2;
foo();
return NULL;
}
void foo() {
printf("Thread %.16lx: foo(), TLS data=%d %d\n",
pthread_self(), TLS_data1, TLS_data2);
bar();
}
void bar() {
printf("Thread %.16lx: bar(), TLS data=%d %d\n",
pthread_self(), TLS_data1, TLS_data2);
return;
}
int main(int argc, char **argv)
{
pthread_t thread[NUMTHREADS];
int rc=0;
int i;
threadparm_t gData[NUMTHREADS];
printf("Enter Testcase - %s\n", argv[0]);
printf("Create/start %d threads\n", NUMTHREADS);
for (i=0; i < NUMTHREADS; i++) {
/* Create per-thread TLS data and pass it to the thread */
gData[i].data1 = i;
gData[i].data2 = (i+1)*2;
rc = pthread_create(&thread[i], NULL, thread_run, &gData[i]);
checkResults("pthread_create()\n", rc);
}
printf("Wait for all threads to complete, and release their resources\n");
for (i=0; i < NUMTHREADS; i++) {
rc = pthread_join(thread[i], NULL);
checkResults("pthread_join()\n", rc);
}
printf("Main completed\n");
return 0;
}
Test and verify it:
weng@weng-u1604:~/codeEx$ gcc -o tls-keyword tls-keyword.c -lpthread
weng@weng-u1604:~/codeEx$ ./tls-keyword
Enter Testcase - ./tls-keyword
Create/start 2 threads
Wait for all threads to complete, and release their resources
Thread 00007f0670791700: Entered
Thread 00007f0670791700: foo(), TLS data=0 2
Thread 00007f0670791700: bar(), TLS data=0 2
Thread 00007f066ff90700: Entered
Thread 00007f066ff90700: foo(), TLS data=1 4
Thread 00007f066ff90700: bar(), TLS data=1 4
Main completed
weng@weng-u1604:~/codeEx$
#Use “pthread_create_key() / pthread_delete_key()” to for bug chunk of data
Since the storage area for TLS is limited, and if there is a big chunk of datas/pbjects are to be stored in TLS, it can be organized into a struct and use “pthread_create_key() /pthread_delete_key()”.
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
typedef struct TLS_Big_data_ {
int thread_id;
int data[2048];
} TLS_Big_data;
void * thread_run(void *);
void show_my_tls();
pthread_key_t thr_id_key;
void main(int argc, void ** argv)
{
pthread_t thread;
TLS_Big_data * tls_data;
int i;
pthread_key_create(&thr_id_key, NULL);
for(i = 1; i <= 10; i++)
{
tls_data = (TLS_Big_data *)malloc(sizeof(TLS_Big_data));
tls_data->thread_id = i;
pthread_create(&thread, NULL,
thread_run, (void *)(tls_data));
}
pthread_exit(NULL);
}
void * thread_run(void * param)
{
void *tls_val = param;
pthread_setspecific(thr_id_key, tls_val);
show_my_tls();
/* release the meory held by TLS*/
TLS_Big_data * tls_data;
tls_data = (TLS_Big_data *)pthread_getspecific(thr_id_key);
if (tls_data) free(tls_data);
return NULL;
}
void show_my_tls()
{
TLS_Big_data * tls_data;
tls_data = (TLS_Big_data *)pthread_getspecific(thr_id_key);
if (tls_data) {
printf("Thread %lx holds TLS has %d\n", pthread_self(),
tls_data->thread_id);
} else {
printf("Thread %lx TLS data not found\n", pthread_self());
}
}
Compile and run it to verify:
weng@weng-u1604:~/codeEx$ gcc -o tls-use-key tls-use-key.c -lpthread
weng@weng-u1604:~/codeEx$ ./tls-use-key
Thread 7fb46fdab700 holds TLS has 3
Thread 7fb46f5aa700 holds TLS has 4
Thread 7fb46eda9700 holds TLS has 5
Thread 7fb46e5a8700 holds TLS has 6
Thread 7fb46dda7700 holds TLS has 7
Thread 7fb46d5a6700 holds TLS has 8
Thread 7fb46cda5700 holds TLS has 9
Thread 7fb46c5a4700 holds TLS has 10
Thread 7fb470dad700 holds TLS has 1
Thread 7fb4705ac700 holds TLS has 2
weng@weng-u1604:~/codeEx$
Subscribe via RSS