首先看一下百科上面的解释:
英文为Thread Local Storage,缩写为TLS。为什么要有TLS?原因在于,全局变量与函数内定义的静态变量,是各个线程都可以访问的共享变量。
在一个线程修改的内存内容,对所有线程都生效。这是一个优点也是一个缺点。说它是优点,线程的数据交换变得非常快捷。说它是缺点,一个线程死掉了,其它线程也性命不保; 多个线程访问共享数据,需要昂贵的同步开销,也容易造成同步相关的BUG。
如果需要在一个线程内部的各个函数调用都能访问、但其它线程不能访问的变量(被称为static memory local to a thread 线程局部静态变量),就需要新的机制来实现。这就是TLS。
线程局部存储在不同的平台有不同的实现,可移植性不太好。幸好要实现线程局部存储并不难,最简单的办法就是建立一个全局表,通过当前线程ID去查询相应的数据,因为各个线程的ID不同,查到的数据自然也不同了。但Windows系统采用了每个线程建线程专享的索引表,表的条目为线程局部存储的地址。在线程执行的任何代码处,都可以查询本线程的这个索引表获得要访问的线程局部存储的地址。
大多数平台都提供了线程局部存储的方法,无需要我们自己去实现
这里看一下Linux是怎么实现的。
linux实现
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
int pthread_key_delete(pthread_key_t key);
void *pthread_getspecific(pthread_key_t key);
int pthread_setspecific(pthread_key_t key, const void *value);
下面说一下线程存储的具体用法。
1) 创建一个类型为 pthread_key_t 类型的变量。
2)调用 pthread_key_create() 来创建该变量。该函数有两个参数,第一个参数就是上面声明的 pthread_key_t 变量,
第二个参数是一个清理函数,用来在线程释放该线程存储的时候被调用。该函数指针可以设成 NULL ,这样系统将调用默认的清理函数。
3)当线程中需要存储特殊值的时候,可以调用 pthread_setspcific() 。该函数有两个参数,第一个为前面声明的 pthread_key_t 变量,
第二个为 void* 变量,这样你可以存储任何类型的值。
4) 如果需要取出所存储的值,调用 pthread_getspecific() 。该函数的参数为前面提到的 pthread_key_t 变量,该函数返回
void * 类型的值。
实例:
#include <malloc.h>
#include <pthread.h>
#include <stdio.h>
static pthread_key_t thread_log_key;
void close_thread_log (void* thread_log)
{
}
pthread_mutex_t smc_threadMutex;
void* thread_function (void* args)
{
char thread_log_filename[20];
FILE* thread_log;
int threadId = 0;
int temp = 0;
int *threadId_2 = temp;
threadId = pthread_self();
pthread_mutex_lock(&smc_threadMutex); //加锁,否则打印出来的结果可能次序不对
printf("my threadId is %d.\n", threadId);
pthread_setspecific (thread_log_key, threadId);
threadId_2 = (int*)pthread_getspecific (thread_log_key);
printf("my threadId_2 is %d.\n", *threadId_2);
pthread_mutex_unlock(&smc_threadMutex);
sleep(2);
// write_to_thread_log ("Thread starting.");
/* Do work here... */
return NULL;
}
int main ()
{
int i;
pthread_t threads[5];
/* Create a key to associate thread log file pointers in
thread-specific data. Use close_thread_log to clean up the file
pointers. */
pthread_mutex_init(&smc_threadMutex, NULL);
pthread_key_create (&thread_log_key, close_thread_log);
/* Create threads to do the work. */
for (i = 0; i < 5; ++i)
pthread_create (&(threads[i]), NULL, thread_function, NULL);
/* Wait for all threads to finish. */
for (i = 0; i < 5; ++i)
pthread_join (threads[i], NULL);
return 0;
}
使用gcc pthread_key.c -lpthread
运行结果:
root@leaves-desktop:/home/leaves/android/temp# ./a.out
my threadId is -1249662144.
my threadId_2 is -1249662144.
my threadId is -1241269440.
my threadId_2 is -1241269440.
my threadId is -1232876736.
my threadId_2 is -1232876736.
my threadId is -1224484032.
my threadId_2 is -1224484032.
my threadId is -1216091328.
my threadId_2 is -1216091328.
root@leaves-desktop:/home/leaves/android/temp#