线程本地存储(TLS)
线程本地存储(TLS, Thread-local Storage)是一种声明全局变量/静态变量为线程本地变量的实现方法(每个线程都有自己独立的实例)。
典型的一种使用场景是MemPool:
- 每个线程有自己TLS ObjectList,维持一定数量的对象;
- 分配对象时,如果TLS ObjectList有可用对象,直接分配,否则加锁后从MemPool
分配;
- 释放对象时,如果TLS ObjectList少于一定数量,加入到TLS ObjectList返回,
否则加锁后将一批对象放回到MemPool。
GCC使用关键词 __thread
声明局部变量。如下是一个例子,其中 value
是一个
TLS变量。
#include <assert.h> #include <pthread.h> #include <stdio.h> #include <unistd.h> pthread_key_t test_key1; pthread_key_t test_key2; __thread unsigned long value; void destruct_test_key1(void *p) { printf("<Func %s>: thread(%u) p=%p, value=%p/%lu\n", __FUNCTION__, pthread_self(), p, &value, value); } void destruct_test_key2(void *p) { printf("<Func %s>: thread(%u) p=%p, value=%p/%lu\n", __FUNCTION__, pthread_self(), p, &value, value); } void* thread_func(void *arg) { usleep((unsigned long)arg % 1000); printf("<Func %s>: thread(%u) arg(%lu)\n", __FUNCTION__, pthread_self(), (unsigned long)arg); if ((unsigned long)arg == 1) { pthread_setspecific(test_key1, &value); value = 1000; } if ((unsigned long)arg == 2) { pthread_setspecific(test_key2, &value); value = 2000; } return NULL; } int main(int argc, char *argv[]) { int ret; ret = pthread_key_create(&test_key1, &destruct_test_key1); assert(ret == 0); ret = pthread_key_create(&test_key1, &destruct_test_key2); assert(ret == 0); pthread_t tid; ret = pthread_create(&tid, NULL, &thread_func, (void*)(unsigned long)1); assert(ret == 0); ret = pthread_create(&tid, NULL, &thread_func, (void*)(unsigned long)2); assert(ret == 0); ret = pthread_create(&tid, NULL, &thread_func, (void*)(unsigned long)3); assert(ret == 0); usleep(10000); return 0; }
编译 gcc -o tls tls.c -lpthread
执行结果:
yanyg@t430:~/test$ ./tls <Func thread_func>: thread(3569612544) arg(3) <Func thread_func>: thread(3578005248) arg(2) <Func destruct_test_key1>: thread(3578005248) p=0x7f4fd54406f8, value=0x7f4fd54406f8/2000 <Func thread_func>: thread(3586397952) arg(1) <Func destruct_test_key2>: thread(3586397952) p=0x7f4fd5c416f8, value=0x7f4fd5c416f8/1000
References