muduo_base代码剖析之线程安全的Sigleton模式

版权声明:guojawee https://blog.csdn.net/weixin_36750623/article/details/84324753

预备知识

  1. 什么是单例模式?
    一个类有且仅有一个实例,并且对外提供统一的访问该实例的接口
  2. 单例模式分为饿汉式、懒汉式,对于饿汉式要保证线程安全需要使用double-check lock机制
  3. muduo中实现的线程安全的Sigleton类,没使用锁,而使用效率更高的线程一次性初始化函数

上述讲解的内容比较基础,不懂的同学可以自行百度

moduo的线程安全的Sigleton类的源码分析

  1. 使用一次性初始化函数pthread_once(&ponce_, &Singleton::init),保证value_ = new T()语句只能被执行一次,即只创建一个
  2. 使用模板机制,Singleton将各种类T包装成线程安全的单例类
  3. atexit
    ::atexit(destroy);
    在init 函数内注册destroy,在程序结束时会调用destroy,在destroy内部delete value_;
  4. typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1];
    假设class A; A* p; delete p; 现在A只是前向声明,是不完全类型,那么delete p会出问题,但在编译时只是报警告。
    sizeof(A) == 0; 故 typedef char T_must[-1]; 在编译时就会出错。
template<typename T>
class Singleton : noncopyable
{
 private:
  static pthread_once_t ponce_;
  static T*             value_; //唯一的实例对象指针
  
 public:
  Singleton() = delete;
  ~Singleton() = delete;

  //即使多个线程都调用了instance()函数
  //pthread_once还是能保证init()函数只被执行一次
  //这种方式比使用锁的效率高
  static T& instance()
  {
    pthread_once(&ponce_, &Singleton::init); 
    assert(value_ != NULL);
    return *value_;
  }

 private:
  static void init() //创建对象
  {
    value_ = new T();
    if (!detail::has_no_destroy<T>::value)
    {
      ::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;
  }
};

template<typename T>
pthread_once_t Singleton<T>::ponce_ = PTHREAD_ONCE_INIT;

template<typename T>
T* Singleton<T>::value_ = NULL;

测试代码

单例模式的使用,就是将自定义的类,作为模板参数T传给Singleton

#include <muduo/base/Singleton.h>
#include <muduo/base/CurrentThread.h>
#include <muduo/base/Thread.h>

#include <stdio.h>

class Test : muduo::noncopyable
{
 public:
  Test()
  {
    printf("tid=%d, constructing %p\n", muduo::CurrentThread::tid(), this);
  }

  ~Test()
  {
    printf("tid=%d, destructing %p %s\n", muduo::CurrentThread::tid(), this, name_.c_str());
  }

  const muduo::string& name() const { return name_; }
  void setName(const muduo::string& n) { name_ = n; }

 private:
  muduo::string name_;
};

void threadFunc()
{
  //打印name	
  printf("tid=%d, %p name=%s\n",
         muduo::CurrentThread::tid(),
         &muduo::Singleton<Test>::instance(),
         muduo::Singleton<Test>::instance().name().c_str());
		 
  //更改name = "only one, changed";
  muduo::Singleton<Test>::instance().setName("only one, changed"); 
}

int main()
{
  //使用Singleton类,将自定义的Test封装成线程安全的单例类	
  muduo::Singleton<Test>::instance().setName("only one");
  
  muduo::Thread t1(threadFunc); //子线程
  t1.start();
  t1.join();
  
  //打印name,因为单例模式,共享的是同一个实例,因此打印结果name为修改后的值only one, changed
  printf("tid=%d, %p name=%s\n", //主线程
         muduo::CurrentThread::tid(),
         &muduo::Singleton<Test>::instance(),
         muduo::Singleton<Test>::instance().name().c_str());
}

猜你喜欢

转载自blog.csdn.net/weixin_36750623/article/details/84324753
今日推荐