先介绍一下单例模式:
https://www.cnblogs.com/sunchaothu/p/10389842.html
上文所讲的几种单例模式从懒汉式(Lazy-Initialization)的方法升级到使用锁机制和智能指针,再升级到使用局部静态变量(关于静态变量的特性:如果当变量在初始化的时候,并发同时进入声明语句,并发线程将会阻塞等待初始化结束),对加深C++特性大有帮助。
但在muduo库中采用有pthread_once实现单例模式:
#ifndef MUDUO_BASE_SINGLETON_H
#define MUDUO_BASE_SINGLETON_H
#include "muduo/base/noncopyable.h"
#include <assert.h>
#include <pthread.h>
#include <stdlib.h> // atexit
namespace muduo
{
namespace detail
{
// This doesn't detect inherited member functions!
// http://stackoverflow.com/questions/1966362/sfinae-to-check-for-inherited-member-functions
template<typename T>
struct has_no_destroy
{
template <typename C> static char test(decltype(&C::no_destroy));
template <typename C> static int32_t test(...);
const static bool value = sizeof(test<T>(0)) == 1;
};
} // namespace detail
template<typename T>
class Singleton : noncopyable
{
public:
Singleton() = delete;
~Singleton() = delete;
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);//atexit用来设置在程序正常结束前调用的函数
//程序结束自动销毁
}
}
static void destroy()
{
typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1];//T必须为完整的类型,否则报错,而不是警告
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;
} // namespace muduo
#endif // MUDUO_BASE_SINGLETON_H
pthread_once函数
int pthread_once(pthread_once_t *once_control, void (*init_routine) (void));
pthread_once_t Singleton<T>::ponce_ = PTHREAD_ONCE_INIT;
功能:本函数使用初值为PTHREAD_ONCE_INIT的once_control变量保证init_routine()函数在本进程执行序列中仅执行一次。
Linux Threads使用互斥锁和条件变量保证由pthread_once()指定的函数执行且仅执行一次,而once_control表示是否执行过。
如果once_control的初值不是PTHREAD_ONCE_INIT(Linux Threads定义为0),pthread_once() 的行为就会不正常。
static变量:
- 一个类中可以有一个或多个静态成员变量,所有的对象都共享这些静态成员变量,都可以引用它。
- static 成员变量和普通 static 变量一样,都在内存分区中的全局数据区分配内存,到程序结束时才释放。这就意味着,static 成员变量不随对象的创建而分配内存,也不随对象的销毁而释放内存。而普通成员变量在对象创建时分配内存,在对象销毁时释放内存。
- 静态成员变量必须初始化,而且只能在类体外进行。
- 初始化时可以赋初值,也可以不赋值。如果不赋值,那么会被默认初始化为0。
- 静态成员变量既可以通过对象名访问,也可以通过类名访问,但要遵循 private、protected 和 public 关键字的访问权限限制。当通过对象名访问时,对于不同的对象,访问的是同一份内存