有关线程局部存储

来源:互联网 发布:兼职微信公众号源码 编辑:程序博客网 时间:2024/05/17 09:10

首先看一下百科上面的解释:

英文为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 inthread-specific data. Use close_thread_log to clean up the filepointers. */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.outmy 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#