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$