[size=medium]
线程私有数据的使用场景是:某个函数在第一次被调用的时候,分配内存block,在以后每次调用的时候,都是用第一次所分配的内存block,无需再次分配。可以用线程私有数据来存储这个内存block。
在多线程环境下,如果不使用线程私有数据,由于函数只分配了一个block,所以各个线程在block上必然会有竞争。如果每个线程对这个block的使用是相互独立的,比如对errno的设置,就可以使用线程私有变量来避免竞争。
可以把线程私有变量看成是一种类型的数据结构,对于同一个key,不同的线程可以有不同的value。Linux为这种数据结构提供了GET和SET接口,即:[/size]
void *pthread_getspecific(pthread_key_t key);//获取key所对应的线程私有数据
int pthread_setspecific(pthread_key_t key, const void *value); //设置key所对应的线程私有数据
[size=medium]
一般而言,比如key是全局变量,需要通过pthread_key_create(&key, destructor)初始化key。线程1调用pthread_setspecific(key, value1);设置了key所对应的值value1。这种设置在另外一个线程2是不可见的,即线程2通过pthread_getspecific(key)是获取不到value1的。同样线程2通过pthread_setspecific(key, value2)对线程1也没有任何影响。
总的来说,就是对于同一个pthread_key,每个线程都对value有一个独立的副本,所以避免了竞争。
具体例子如下,例子来源于《The Linux Programming Interface - A Linux and UNIX System Programming Handbook》:[/size]
#include
#include /* Get declaration of strerror() */
#include
static pthread_once_t once = PTHREAD_ONCE_INIT;
static pthread_key_t strerrorKey;
#define MAX_ERROR_LEN 256 /* Maximum length of string in per-thread
buffer returned by strerror() */
/* Free thread-specific data buffer */
static void destructor(void *buf) {
free(buf);
}
/* One-time key creation function */
static void createKey(void) {
int s;
/* Allocate a unique thread-specific data key and save the address
of the destructor for thread-specific data buffers */
e s = pthread_key_create(&strerrorKey, destructor);
if (s != 0)
errExitEN(s, "pthread_key_create");
}
char * strerror(int err) {
int s;
char *buf;
/* Make first caller allocate key for thread-specific data */
r s = pthread_once(&once, createKey);
if (s != 0)
errExitEN(s, "pthread_once");
t buf = pthread_getspecific(strerrorKey);
if (buf == NULL) { /* If first call from this thread, allocate
buffer for thread, and save its location */
y buf = malloc(MAX_ERROR_LEN);
if (buf == NULL)
errExit("malloc");
u s = pthread_setspecific(strerrorKey, buf);
if (s != 0)
errExitEN(s, "pthread_setspecific");
}
if (err < 0 || err >= _sys_nerr || _sys_errlist[err] == NULL) {
snprintf(buf, MAX_ERROR_LEN, "Unknown error %d", err);
} else {
strncpy(buf, _sys_errlist[err], MAX_ERROR_LEN - 1);
buf[MAX_ERROR_LEN - 1] = '\0'; /* Ensure null termination */
}
return buf;
}
[size=medium]
thread local和线程私有数据在概念上差不多,thread local为线程私有数据提供了更方便的访问接口。
如下例子[/size]
static __thread char local_buf[MAX_ERROR_LEN];
[size=medium]
定义static变量local_buf,通过__thread修饰,则每个线程都对local_buf,都会有一个独立的副本,它们自己不会相互干扰
通过如下程序的输出,我们可以看到,不同的线程local_buf的地址是不同的,所以每个线程可以独立的对buf修改。[/size]
#include
#include
#include
#define MAX_ERROR_LEN 10240
static char normal_buf[MAX_ERROR_LEN];
static __thread char local_buf[MAX_ERROR_LEN];
void * func(void * arg) {
printf("thread %x : local_buf %x\n", pthread_self(), local_buf);
printf("thread %x : normal_buf %x\n", pthread_self(), normal_buf);
}
int main() {
pthread_t tid;
pthread_create(&tid, NULL, func, NULL);
func(NULL);
pthread_join(tid, NULL);
return 0;
}