Using a single case pattern in design mode to implement the Boost library _c language for C + +

Source: Internet
Author: User

Thread-Safe single case mode
Lazy mode
: That is, the first time the class instance is invoked, a new instance of that class is generated, and only this instance is returned at a later time.

Locks are required to ensure thread safety: Reason: Multiple threads may enter an If statement that determines whether an instance already exists, thereby non thread safety.

Use double-check to ensure thread safety. However, if a large amount of data is processed, the lock becomes a serious performance bottleneck.

1, static member instances of the lazy mode:

Class Singleton
{
private:
  static singleton* m_instance;
  Singleton () {} public
:
  static singleton* getinstance ();
 
singleton* singleton::getinstance ()
{
  if (NULL = = m_instance)
  {
    Lock ();
Use other classes to implement, such as Boost
    if (NULL = m_instance)
    {
      m_instance = new Singleton;
    }
    UnLock ();
  }
  return m_instance;
}

2, internal static instances of the lazy model

It should be noted here that after c++0x, the compiler is required to guarantee the thread safety of internal static variables, without locking. But before C + + 0X, you still need to lock.

Class Singletoninside
{
private:
  singletoninside () {} public
:
  static singletoninside* getinstance ()
  {
    Lock (); 
Not needed after c++0x
    static singletoninside instance;
    UnLock (); 
Not needed after c++0x return
    instance; 
  }
;

second, a hungry man mode: that is, whether or not an instance of the class is invoked, an instance of the class is generated at the beginning of the program, and only this instance is returned at a later time.

The static initialization instance guarantees its thread security, WHY? Because the static instance initialization is initialized by the main thread in a single-threaded manner before the program begins to enter the main function, there is no need to worry about multithreaded issues.

Therefore, in the performance demand is high, should use this mode, avoid frequent lock contention.

Class Singletonstatic
{
private:
  static const singletonstatic* m_instance;
  Singletonstatic () {} public
:
  static const singletonstatic* getinstance ()
  {return
    m_instance;
  }
};
 
External initialization before invoke main
const singletonstatic* singletonstatic::m_instance = new Singletonstatic;


example of implementation of boost library

Single example is a very simple pattern, implementation should also be very simple, but the simple implementation of C + + Single example will have some pits, with the above thread-safe foundation, below to see how to avoid these pits step-by-step evolution to boost library implementation mode.

Programme I

Class Qmmanager
{public
:
  static Qmmanager &instance ()
  {
    static qmmanager instance_;
    Return Instance_
  }
}

This is the simplest version, in a single thread (or under c++0x) is no problem, but in multithreading is not, because the static Qmmanager Instance_, this sentence is not thread-safe.
At compile time, a static variable under a local scope creates an additional variable that identifies whether the static variable is initialized, and the compiler becomes the following (pseudo code):

Static Qmmanager &instance ()
{
  static bool constructed = FALSE;
  static uninitialized Qmmanager Instance_;
  if (!constructed) {
    constructed = true;
    New (&s) Qmmanager; Construct it
  } return
  Instance_
}

There are competitive conditions, when two threads call instance () at the same time, one thread runs to the IF statement has not set the constructed value, then switch to another thread, constructed value or false, also into the IF statement to initialize the variable, All two threads perform the initialization of this single instance class, which is no longer a single instance.

Programme II
One solution is lock:

Static Qmmanager &instance ()
{
  lock ();//Lock yourself to implement
  static Qmmanager Instance_;
  UnLock ();
  return instance_;
}

However, each call to the instance () lock unlock, the price is slightly greater.

Programme III
then again, change the internal static instance into a static member of the class, and initialize it externally, that is, when you include the file, the main function initializes the instance before it is executed, and the thread does not get back into the problem:

Class Qmmanager
{
protected:
  static Qmmanager instance_;
  Qmmanager ();
  ~qmmanager () {};
Public:
  static Qmmanager *instance ()
  {return
    &instance_;
  }
  void Do_something ();
Qmmanager Qmmanager::instance_; External initialization

This is called the A Hungry Man mode, and the program is initialized as soon as it is loaded, whether or not it is invoked.
It seems to be fine, but there's still a hole in the 2B case: There may be a problem with the method of invoking another single instance class in the constructor of this single instance class.
See Example:

//.h class Qmmanager {protected:static qmmanager;
  Qmmanager ();
~qmmanager () {};
  Public:static Qmmanager *instance () {return &instance_;
 
}
};
  Class Qmsqlite {protected:static qmsqlite instance_;
  Qmsqlite ();
~qmsqlite () {};
  Public:static qmsqlite *instance () {return &instance_;
} void Do_something ();
 
};
Qmmanager Qmmanager::instance_;

Qmsqlite Qmsqlite::instance_;
  . cpp Qmmanager::qmmanager () {printf ("Qmmanager constructor\n");
Qmsqlite::instance ()->do_something (); } qmsqlite::qmsqlite () {printf ("Qmsqlite constructor\n");} void Qmsqlite::d o_something () {printf ("Qmsqlite Do_som
Ething\n "); }

Here the Qmmanager constructor calls the Qmsqlite instance function, but Qmsqlite::instance_ may not have been initialized at this time.
The execution process here: After the program starts, executes to Qmmanager Qmmanager::instance_ before executing main, initializes the Instance_ static variable in Qmmanager, calls to the Qmmanager constructor, Call Qmsqlite::instance () in the constructor, and take the Instance_ static variable in Qmsqlite, but the problem arises when Qmsqlite::instance_ is not initialized.
Is it going to be crash here? Test results are not, this should be related to the compiler, the static data space should be allocated first, before calling the Qmmanager constructor, the Qmsqlite member function in memory already exists, but it has not yet been transferred to its constructor, so the output is this:

Qmmanager constructor
qmsqlite do_something
Qmsqlite Constructor

Programme IV
How to solve this problem, the single example object as static local variable thread security problem, as a class static global variable at the beginning of initialization, there are more than 2 B problem, that combined with the above two ways, can solve these two problems. Boost is implemented as a single instance object as a static local variable, but adding a secondary class allows a single instance object to be initialized at the outset. As follows:

. h
Class Qmmanager
{
protected:
  struct object_creator
  {
    object_creator ()
    {
      Qmmanager::instance ();
    }
    inline void do_nothing () const {}
  };
  Static Object_creator create_object_;
 
  Qmmanager ();
  ~qmmanager () {};
Public:
  static Qmmanager *instance ()
  {
    static qmmanager instance;
    Return &instance;
  }
};
Qmmanager::object_creator qmmanager::create_object_;
 
Class Qmsqlite
{
protected:
  qmsqlite ();
  ~qmsqlite () {};
  struct Object_creator
  {
    object_creator ()
    {
      qmsqlite::instance ();
    }
    inline void do_nothing () const {}
  };
  Static Object_creator create_object_;
Public:
  static Qmsqlite *instance ()
  {
    static qmsqlite instance;
    Return &instance;
  }
  void Do_something ();
 
Qmmanager::object_creator qmmanager::create_object_;
Qmsqlite::object_creator qmsqlite::create_object_;

With the. CPP of Scenario 3, you can see the correct output and invocation:

Qmmanager Constructor
Qmsqlite constructor
qmsqlite do_something

Take a look at the implementation process here:
Initializes the Qmmanager class global static variable create_object_
-> calls the Object_creator constructor
-> invoke the Qmmanager::instance () method to initialize a single instance
-> performs Qmmanager constructors
-> Call Qmsqlite::instance ()
-> Initializes a local static variable Qmsqlite instance
-> executes the Qmsqlite constructor, and then returns this single example.
The difference from scenario three is that when Qmmanager invokes the Qmsqlite, Scenario 3 is taken to a global static variable, where the variable is not initialized, and the single instance of scenario four is a static local variable, and the call is initialized at this time.
The difference from the original scenario is that a single instance is initialized before the main function and does not have a thread security problem.

Final boost
above in order to clarify the point to go in addition to the template, the actual use is a template, do not write so many duplicate code, this is the model of boost library implementation:

Template <typename t>
struct Singleton {struct Object_creator {object_creator
    () { Singleton<t>::instance (); }
    inline void do_nothing () const {}
  };
 
  Static Object_creator Create_object;
 
Public:
  typedef T object_type;
  Static object_type& instance ()
  {
    static object_type obj;
    It is said that this do_nothing is to ensure that the Create_object constructor is called
    //This is related to the compilation of the template
    create_object.do_nothing ();
    return obj;
  }
 
;
Template <typename t> TypeName singleton<t>::object_creator
 
singleton<t>::create_object; Class Qmmanager
{
protected:
  Qmmanager ();
  ~qmmanager () {};
  Friend Class singleton<qmmanager>;
Public:
  void do_something () {};
};
 
int main ()
{
  singleton<qmmanager>::instance ()->do_something ();
  return 0;
}

In fact, boost library such as the implementation of a few patches, using a number of Chine, although it does bypass the pit to achieve the demand, but it feels very bad.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.