|
Serialization
|
main
is called
regardless of where they might be referenced within the program.
In a multi-tasking system, this guarantees that there will be no
race conditions during the construction of any instance. No
thread locking is required to guarantee this.
const
instances are thread-safe during the whole program. Again, no
thread locking is required.
main
is called.
For a more general purpose usage, thread locking on this
singleton could easily be implemented. But as the serialization
library didn't require it, it wasn't implemented.
namespace boost {
namespace serialization {
template <class T>
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();
static bool is_destroyed();
true
if the destructor on this singleton has been
called. Otherwise, return false
.
singleton<T>
, the type T must be default constructible.
It doesn't require static variables - though it may have them.
Since the library guarantees that only one instance of
singleton<T>
exists and all access is through the above static interface
functions, common member functions of T become
the functional equivalent of
static
functions.
The first way is illustrated by an excerpt from the file
extended_type_info.cpp
.
which contains the following code:
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);
...
}
Just by referring to the singleton instance anywhere in the program
will guarantee that one and only one instance for the specified
type (ktmap
in this example)
will exist throughout the program. There is no need for any other
declaration or definition.
A second way is to use
singleton<T>
as one of the base classes of the type. This is illustrated by a simplified
excerpt from
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(){}
...
};
This usage will permit a more natural syntax to be used:
extended_type_info_typeid<T>::get_const_instance()
Again, including one or more of the above statements anywhere
in the program will guarantee that one and only one instance
is created and referred to.
Do not call get_mutable_instance when more than one thread is running! All singletons used in the serialization library follow this rule. In order to help detect accidental violations of this rule there exist singleton lock/unlock functions.
void boost::serialization::singleton_module::lock();
void boost::serialization::singleton_module::unlock();
bool boost::serialization::singleton_module::is_locked();
In a program compiled for debug, any invocation of
get_mutable_instance()
while the library is in a "locked" state will trap in an assertion.
The singleton module lock state is initialized as "unlocked" to permit
alteration of static variables before
main
is called.
The lock()
and
unlock()
are "global"
in that they affect ALL the singletons defined by this template.
All serialization tests invoke lock()
at the start of the program. For programs compiled in release
mode these functions have no effect.
© Copyright Robert Ramey 2007. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)