单例
//singleton.h
template<typename T>
class Singleton : noncopyable
{
public:
...
static T& instance()
{
//保证只在第一次调用时,触发init方法,实现单例。且线程安全,效率高
pthread_once(&ponce_, &Singleton::init);
assert(value_ != NULL);
return *value_;
}
static void init()
{
value_ = new T();
if (!detail::has_no_destroy<T>::value)
{
::atexit(destroy);//atexit:程序结束时调用destroy
}
}
static void destroy()
{
typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1];
T_must_be_complete_type dummy; (void) dummy;
delete value_;
value_ = NULL;
}
private:
static pthread_once_t ponce_;
static T* value_;
};
template<typename T>
pthread_once_t Singleton<T>::ponce_ = PTHREAD_ONCE_INIT;
template<typename T>
T* Singleton<T>::value_ = NULL;
};
-
typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1];
typedef char A[10], 则A代表char[10]数组类型;
若T为不完全类型(如只声明未定义),则在编译期就会报错(数组[ ]中不能小于0) 。 -
(void)dummy
(void)变量:告诉编译器,我用了这个变量,不用警告。
用法示例:方法foo(int a, int b); 某次更新后在其定义中不再使用形参b,但之前仍有很多其他方法或程序调用了此方法。为了不修改其他程序,则foo形参数目也不能改,此时编译器会发出警告(未使用参数);在定义中添加"(void)b;" 则不会发出警告,与其他程序无缝衔接。
ThreadLcoal封装
多线程环境下,全局变量会共享。但有时我们需要线程私有的全局变量,仅在某个线程中有效,却可以跨多个函数访问。
POSIX线程库通过维护一定的数据结构来解决,这些数据称为TSD(thread-specific data), 线程特定数据也称为线程本地存储TLS(thread-local storage)。对于POD类型的TLS,可以使用前面文章提到过的 __thread。
ThreadLocal提供了非POD类型的模板
template<typename T>
class ThreadLocal : noncopyable
{
public:
ThreadLocal()
{
pthread_key_create(&pkey_, &ThreadLocal::destructor);
}
~ThreadLocal()
{
pthread_key_delete(pkey_);
}
T& value()
{
T* perThreadValue = static_cast<T*>(pthread_getspecific(pkey_));
if (!perThreadValue)//若对象还未创建,则创建并绑定
{
T* newObj = new T();
pthread_setspecific(pkey_, newObj);
perThreadValue = newObj;
}
return *perThreadValue;
}
private:
static void destructor(void *x)
{
T* obj = static_cast<T*>(x);
...
delete obj;
}
private:
pthread_key_t pkey_;
};
pthread_key_t pkey_; pkey中存放的是实际数据的地址,即pkey_指向TSD。
pthread_key_create :创建key(需指定回调函数销毁实际数据),每个线程都会创建,但都指向本线程数据
pthread_key_delete :删除key(只是销毁key,不负责销毁数据)
pthread_setspecific :指定key与对应的数据(实际是数据地址)
pthread_getspecific :获取key指向的数据(地址)