本文剖析muduo库的ThreadLocalSingleton类,即线程本地单例类。
先来看下它的类图,它的内部嵌套的一个deleter类。
分析如下:
#ifndef MUDUO_BASE_THREADLOCALSINGLETON_H
#define MUDUO_BASE_THREADLOCALSINGLETON_H
#include <boost/noncopyable.hpp>
#include <assert.h>
#include <pthread.h>
namespace muduo
{
template<typename T>
class ThreadLocalSingleton : boost::noncopyable
{
public:
static T& instance() //返回单例对象,不需要按照线程安全方式实现,因为本身就是__thread类型
{
if (!t_value_) //如果指针为空创建
{
t_value_ = new T();
deleter_.set(t_value_); //把t_value_指针暴露给deleter,为了垃圾回收
}
return *t_value_;
}
static T* pointer()
{
return t_value_;
}
private:
ThreadLocalSingleton();
~ThreadLocalSingleton();
static void destructor(void* obj) //内层类中线程结束时,会调用此函数取清理key指向的数据
{
assert(obj == t_value_);
typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1];
T_must_be_complete_type dummy; (void) dummy;
delete t_value_;
t_value_ = 0;
}
class Deleter
{
public:
Deleter()
{
pthread_key_create(&pkey_, &ThreadLocalSingleton::destructor); //设置外面类的destructor方法,
}
~Deleter()
{
pthread_key_delete(pkey_);
}
void set(T* newObj)
{
assert(pthread_getspecific(pkey_) == NULL); //保证之前key没有指向数据
pthread_setspecific(pkey_, newObj); //现在设置key指向newobj指针,在ThreadLocalSingleton中会传入t_value_指针,
//实际上是为了实现垃圾回收,线程结束时,deleter调用destroy,释放key指向的数据,而这个数据正好就是外部类的成员t_value_指针
}
pthread_key_t pkey_;
};
static __thread T* t_value_; //__thread关键字保证线程局部属性,只能修饰POD类型
static Deleter deleter_; //用来销毁T*指针所指对象
};
template<typename T>
__thread T* ThreadLocalSingleton<T>::t_value_ = 0;
template<typename T>
typename ThreadLocalSingleton<T>::Deleter ThreadLocalSingleton<T>::deleter_;
}
ThreadLocalSingleton和Singleton<ThreadLocal<test>>
(ThreadLocal是上篇博客说过的,线程局部类)
实际上都是一样的,前者是直接集成化单例和线程局部,后者是产生一个单例的模板,然后把线程局部对象以模板参数形式传入,也变成了单例对象。