muduo库-Threadlocal类
muduo库-Threadlocal类
首先来看一个概念:线程特定数据
在单线程程序中,我们经常用全局变量共享数据。多线程环境下,全部变量被所有线程所共有。但有时应用程序设计中有必要提供线程私有的全局变量,仅在某个线程中有效。POSIX线程库通过维护一定的数据结构来解决这个问题,这些数据称之为线程特定数据(Thread-specific Data,或TSD)。对于POD类型,可以用__thread来解决。
POD类型
POD(Plain Old Data)类型是C++ 定义的一类数据结构概念,比如 int、float 等都是 POD 类型的。Plain 代表它是一个普通类型,Old 代表它是旧的,与几十年前的 C 语言兼容,那么就意味着可以使用 memcpy() 这种最原始的函数进行操作。两个系统进行交换数据,如果没有办法对数据进行语义检查和解释,那就只能以非常底层的数据形式进行交互,而拥有 POD 特征的类或者结构体通过二进制拷贝后依然能保持数据结构不变。也就是说,能用 C 的 memcpy() 等函数进行操作的类、结构体就是 POD 类型的数据。
POSIX线程库通过四个函数操作线程特定数据,分别是pthread_key_create
,pthread_key_delete
,pthread_getspecific
,pthread_setspecific
。
一旦某个线程创建了一个key
,比如key[1]
,那么其他线程也有自己的key[1]
,它们通过各自的key[1]
访问到的实际数据(堆上内存分配的空间)是不同的,pthread_key_delete
只是删除key
,实际数据空间的释放需要在pthread_key_create
中注册一个回调函数destructor
去delete T*
。
ThreadLocal
类结构图如下:
类的实现:
1 |
|
muduo库注册的destroy()函数直接将它的入口参数x指针强制转化为T类型指针。然后直接调用delete。这是什么原因呢?
在pthread_key_create()函数中,传入了一个&ThreadLocal::destructor的成员指针,当线成局部变量销毁时,如果传入的第二个参数不为NULL,系统将调用该函数取销毁实际的数据。由于是类成员函数,隐藏了一个指针是this指针,这时候void *x,x的地址实际上就是this的地址,也就是该对象的地址。
上面我们知道,ThreadLocal
类只有一个成员,就是pthread_key_t
类型成员pkey_
(不是指针类型),我们可以再回头看pthread_key_create()
函数,我们发现它传入的第一个参数正是pkey_的地址,也就是pthread_key_t*类型。所以我们在destructor()
函数中使用
1 |
|
由于pkey_
是传入pthread_key_create()
的第一个参数,所以它的地址就是实际数据存放的地址。而(void*)this == (void*)&pkey_
,所以直接强制转化this
指针为T*
类型,然后以T*
类型的方式delete
,就会真实释放线程局部存储的数据。
参考: