Motivation:
serialization library依赖一系列的静态变量和存储运行时类型的信息的表。例如存储名字和对应类型的表。存储基类和派生类的关系的表。构造,析构和静态变量的使用需要参考一下机制:
*一些静态变量和常量指向别人。初始化的必须合理有序而不能是随意的。
*一些静态变量并没有显示指定,并且没有特殊的预定义,将会被许多编译优化选项去掉
* 这些变量大多都是用模板创建的必须确保他们被实例化
*在多线程系统中,这些静态变量将会被不同的线程并发访问,这将会产生竞争的现象。其结果是无法预期的。
这个单例类解决了上诉的所有问题。
Feature:
此单例的实现拥有一下特性。
*所有的单例将会在被使用前构造完成。
*所有用模板创建的实例确保被实例化。
*无论一个实例是否被显示应用,在构造release模式的可执行文件时,这些实例不会被编译选项优化掉。
*无论该实例在程序中的哪里被应用,所有的实例将在main之前被创建。在多线程机制的系统中这可以保证在创建实例时不会有竞争的现象并且不需要任何锁的机制去确保。
*以上的机制表明所有的const实例在整个程序中是线程安全的,再次强调不需要线程锁机制。
*如果创建一个muteable实例,并在多线程系统中调用main去修改该实例,则存在竞争的现象。serialization library只有在很少的地方用到muteable实例,并且也没有调用main修改该实例的值,线程锁机制是很容易被引用进来防止竞争的现象的,但是serialization library没有用到这种机制,所以就没有实现县城锁的机制。
Class Interface
namespace boost {
namespace serialization {
template
class singleton : public boost::noncopyable
{
public:
static const T & get_const_instance();
static T & get_mutable_instance();
static bool is_destroyed();
};
} // namespace serialization
} // namespace boost
static const T & get_const_instance();
返回一个该类的单例实例的一个常量引用。
static T & get_mutable_instance();
返回一个muteable的引用,指向该类型的单例
static bool is_destroyed();
如果该单例的析构函数被调用了则返回true,否则返回false
Requirements
使用singleton<T>,T必须有默认的构造函数,它并不需要包含静态变量(可能该类包含静态变量),因为该库保证只有一个singleton<T>的实例,并且所有访问通过以上的静态接口,T的公共成员函数等价于静态函数。
Examples
至少有两种不同的方式去使用这个模板类。都在serialization library中使用。
第一种方式通过文件extended_type_info.cpp的再录来说明。其中包含以下代码。
typedef std::set<const extended_type_info *, key_compare> ktmap;
...
void
extended_type_info::key_register(const char *key) {
...
result = singleton<ktmap>::get_mutable_instance().insert(this);
...
}
通过在程序的任何地方指向该单例将会保证只有一个该类型的实例(在本例中类型为ktmap)在本程序中被创建。不需要其他的声明或定义。
第二种方式使用singleton<T>作为类型的基类之一。这通过extended_type_info_typeid.hpp的简化判断来说明。
template<class T>
class extended_type_info_typeid :
public detail::extended_type_info_typeid_0,
public singleton<extended_type_info_typeid<const T> >
{
friend class singleton<extended_type_info_typeid<const T> >;
private:
// private constructor to inhibit any existence other than the
// static one. Note: not all compilers support this !!!
extended_type_info_typeid() :
detail::extended_type_info_typeid_0()
{
type_register(typeid(T));
}
~extended_type_info_typeid(){}
...
};
这种用法将允许使用一个更自然的语法格式。
extended_type_info_typeid<T>::get_const_instance()
再次强调在程序中包含一个或更多的以上的声明将会确保只会创建一个实例。
Multi-Threading
如果按照以下的规则使用该单例则这个单例模式是多线程安全的。
当在多线程环境下不要调用get_mutable_instance。存在一种单例的 lock/unlock函数去检测违反该规则的场景。
void boost::serialization::singleton_module::lock();
void boost::serialization::singleton_module::unlock();
bool boost::serialization::singleton_module::is_locked();
在编译debug模式下,任何包含调用get_mutable_instance(),如果当时该库正处于locked状态,将会陷入assertion。该单例模式在main函数之前被初始化为unlocked,允许修改静态变量。lock()与unlock()都是全局的,他们会影响该模板定义的所有单例。所有序列化测试在程序的开始处调用lock()。当程序在release模式下编译时这些锁函数将没有effect。