什么是线程局部存储
我们知道,在Linux系统中,子线程是通过复制来产生的,由于进程是资源分配的最小单位,那么,进程中的线程除了有自身运行时需要的一些栈空间,寄存器等资源,其余资源都是和其他线程共享的,这就会引入一些资源竞争的问题,为应用程序执行带来不确定性。
而线程存储指的是一种特殊的内存机制,用于将数据存储在当前线程的私有内存中,这样线程就有自己私有的数据存储空间,不会被其他线程所干扰。
C++11起支持定义线程局部变量
实际上,线程局部存储早就出现,由于是一种特殊的内存机制,所以需要操作系统层面的支持。
C语言中早就支持相关功能:
pthread_key_create(&key, NULL);
pthread_setspecific(key, value);
pthread_getspecific(key);
GCC,Clang编译器使用__thread来声明局部变量存储。
C++从2011年语法开始,支持并统一了定义线程局部变量方式,吗thread_local
。
thread_local 解决什么样的问题?
全局变量与静态变量
int gVal_0 = 180;
static int gVal_1 = 100;
全局变量和静态变量是放在进程的.data段,是所有线程共享且可见的,当给该类型数据添加一个thread_local修饰后,变量会多了线程属性,也就是上面两个变量在当前进程的每个线程都会有一份独立的副本,互不干扰。
thread_local int gVal_0 = 180;
thread_local static int gVal_1 = 100;
还有一个典型的案例,有过linux系统开发的同时都知道,我们调用POSIX接口后,如果接口返回错误码或者失败,我们都会获取一下错误码errno,该错误码是一个全局变量,想象一下,一个全局错误码可能被多个线程同时访问,是一件多么可怕的事情。
典型案例:获取并存储当前线程的thread id
thread_local int thread_id = 0;
void GetThreadId()
{
if (thread_cached_tid == 0) {
thread_cached_tid = static_cast<pid_t>(::syscall(SYS_gettid));
}
}
这样,每个线程有一个独立的thread_id 变量,互不干扰。