muduo基础库学习--单例模式、ThreadLocal封装

单例

//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指向的数据(地址)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值