Singleton mode

zhaozj2021-02-08  228

Singleton mode

Dragoncheng

The description of the Singleton mode in the GOF work is to ensure that only one entity is only an entity (INSTANCE) and provides a global access point (Global Access Point).

From its description, it is very simple, but it is complex to implement this mode. There is no so-called "best" solution in Singleton design mode. It is necessary to resolve the specific problem at the time, and the solutions in different environments will be described below.

Detailed explanation of Singleton, please see the book "Design Mode" book in GOF. I am more lazy, I don't want to copy it. J

1 Singleton created

1.1 Gof Singleton

The implementation of the Singleton mode in the GoF work is as follows:

/ * Solution one * /

Class Singleton

{

PUBLIC:

Static Singleton * instance () {// 1

IF (! m_pinstatnce) // 2

m_pinstance = new singleleton; // 3

Return m_pinstance; // 4

}

Private:

Static Singleton * m_pinstatnce; //5

Private:

Singleton (); //6

Singleton (const singleton); //7

Singleton & Operator = (const singleton); // 8

~ Singleton (); // 9

}

Singleton * Singleton: m_pinstatnce = null; // 10

In the above solution, we only generate a Singleton object only when you need to call. The benefit of this is that if the result of the object is expensive, it is a very good strategy that is not often used. But if the instance is frequently called, then some people think that the judgment in instance has reduced efficiency (although it is just a judgment statement ^ _ ^), then we will put the 5th statement

Static Singleton M_INSTATNCE;

In this way, return to & m_instance directly in InstatNCE, without having to make any judgment, and efficiency is also high. (Is it?)

After such modification, we will bring catastrophic consequences:

1: First, it is possible to compile this. This is not possible, saying that m_instance is unable to solve (Visural C 6.0)

Error LNK2001: Unresolved External Symbol "Private: static class singleleton singleton :: m_instance" (? m_instance @ a)

2: If the compiler is passed, it is no problem. the answer is negative.

The first is whether INSTANCE is used, the static variable object is generated when the compiler is compiled, that is, resource consumption is inevitable;

The second is not to ensure that the compiler must first initialize M_instance first. So INSTANCE calls may pass back a Singleton object that has not been constructed. This also means that you cannot guarantee that M_InStance used by any external object is an object that is properly initialized. 1.2 Meyers Singleton

How do we solve this problem, it is actually very simple. A very elegant approach is first proposed by Scott Meyers, so it is also known as Meyers Singleton. It relies on the magical skills of the compiler. That is, the Static object in the function is only initialized when the function is executed for the first time (please pay attention not to static constants).

/ * Decomposition * /

Class Singleton

{

PUBLIC:

Static Singleton * instance () {// 1

Static singleleton sinstance; // 2

Return & Sinstance; // 3

}

Private:

Singleton (); // 4

Singleton (const singleton); //5

Singleton & Operator = (const singleton); //6

~ Singleton (); // 7

}

Draming Defines a Static's Singleton object in Instance to solve the problem of initialization in Instance, which is also smoothly solved the problem that defines the Static member object.

Note that the two cannot be compiled in VC6, and there will be the following error:

Error C2248: 'Singleton :: ~ Singleton': Cannot Access Private Member Declared In Class 'Singleton' E: /WORK/Q/A.H (81): See Dechannel Of 'Singleton :: ~ Singleton'

What is the cause of the wrong cause of this problem? Please think carefully ^ _ ^)

The reason is that after generating the STATIC Singleton object, the compiler will automatically generate a destruction function __destroysingleton, then call ATEXIT () registration, execute __destroysingleton when the program exits. But because Singleton's destructor is private, an access error will be generated. (The bug should be modified in the later compiler)

1.3 Singleton improvement

Let the instance back reference (Reference). If the pointer is passed, the call is likely to tell the delete tune.

1.4 Singleton pays attention to

In the above solution, please pay attention to the processing of constructor and the destructuring function, what is the benefit (please understand, lazy and make L).

2 multi-thread

In the solution, if we run in a multi-threaded environment, what will happen?

The consequence is to cause memory leaks, and there is a possibility that the Singleton object acquired before and later is different (whose reason is to think, after another).

In order to solve this problem, it will be changed to the following:

Singleton & Singleton :: Instance () {

LOCK (m_mutex); // Meaning to get mutex // 1IF (! M_pinstance) {// 2

m_pinstance = new singleleton; // 3

}

UNLOCK (M_Mutex); // 4

Return * m_pinstance; // 5

}

This method will solve the problem that the solution running in a multi-threaded environment, but the result is that the thread attempts to lock M_Mutex will have to wait for the thread when m_mutex is locked. And each cost of performing the lock is great, that is, the solution to this solution is not attractive.

Then we will change the code above to the following:

Singleton & Singleton :: Instance () {

IF (! M_pinstance) {// 1

LOCK (m_mutex); // Meaning to acquire mutex // 2

m_pinstance = new singleleton; // 3

UNLOCK (M_Mutex); // 4

}

Return * m_pinstance; // 5

}

Is there any problem with the result of this modification? NO !!!! The results brought about the results, the reason is the same, will cause memory leakage. At this time, "Double Detection Lock" mode debuts.

The Doug Schmidt and Tim Harrison proposed "Double-check Locking mode" to solve the Multithread Singletons issue.

Singleton & Singleton :: Instance () {

IF (! M_pinstance) {// 1

LOCK (m_mutex); // Meaning to acquire mutex // 2

IF (! M_pinstance) // 3

m_pinstance = new singleton; // 4

Unlock (m_mutex); // 5

}

Return * m_pinstance; //6

}

Please see the third sentence above, this sentence is not a power of determination as a magical power ^ _ ^

The above scheme is perfect. Answer or no !!! (Whether you have been depressed, this is not playing me? Please feel patient, listen to my fine arrival ^ _ ^)

If the compiler on the RISC machine is possible to optimize the above code, perform the third sentence before locking M_Mutex. This is completely possible, as in the first sentence, as in the third sentence, it can be processed according to the principle of code optimization. In this way, we are proud of pride "double detection lock" actually does not work (L)

How to do? Solve. How to deal with it? Simply, we can add a modifier in front of M_Pinstance. What modifier? ......

àvolatile (simple, let us j)

So our complete solution is as follows:

/ * Solution three * /

Class Singleton

{

PUBLIC:

Static Singleton & Instance () {// 1

IF (! m_pinstatnce) {// 2

LOCK (m_mutex) // 3if (! M_pinstance) // 4

m_pinstance = new startleton; // 5

Unlock (m_mutex); //6

}

Return * m_pinstance; // 7

}

Private:

Static volatitle singleton * m_pinstatnce; // 8

Private:

Singleton (); // 9

Singleton (const singleton); // 10

Singleton & Operator = (const singleton); // 11

~ Singleton (); // 12

}

Singleton * Singleton: m_pinstatnce = null; // 13

3 Singleton destroyed

Here, we have come to Singleton's simplest and most complicated place.

Why is it simple? We can't ignore the destruction of M_Pinstance created. Because though we have not deleted the Singleton object, it will not cause memory leakage. Why do you say this way? Because only when you assign the accumulated row data and lose all of his Reference, memory leakage happens. The situation that does not belong to Singleton does not have the above situation, there is no cumulative stuff, and until we have its reference. In a modern operating system, the process will be completely released when the process is completed. (You can refer to "Effective C " Terms 10, which is described in memory leaks).

But sometimes leaks still exist, what is it? It is the resource leak. For example, if the Singleton object is managed by a network connection, an OS mutex, a process-friendly Handles, etc. At this time we must take into account the destruction of Singleton. Talking about the destruction, it is a complex topic (two days and three nights can't finish ^ _ ^ joking, everyone is relaxing).

We need to delete the Singleton object in the appropriate location, and we must create or recreate the Singleton object in the appropriate timing.

In our "decision", the destructor of Singleton will automatically invoke Singleton at the end of the program, and the acquired resources will be automatically released. In most cases, it can work effectively. What is the special situation?

We use the KDL (Keyboard, Display, LOG) model, where K, D, and L use the Singleton mode. As long as Keyboard or Display exceptions, we must call LOG to write it into the log, otherwise the log object should not be created. For later one, we can satisfy when our Singleton is created.

In the previous, we have said that when an object is generated (an object generated by NEW), the compiler automatically invokes the ATEXIT (__ destroyObject) function to implement the sect operation of the object. The C object destructor is LIFO, that is, the first object is destroyed.

If the log object is called in general, then the object is destroyed. According to "First destruction first destruction" principle: log object will be destroyed, then the Display object is destroyed. At this time, Display has an exception in destruction, so that the log object is recorded. But in fact, the log object has been destroyed, then calling the log object will generate unpredictable consequences, this problem we call the dead reference. So the previous solution can't solve the problems we have encountered. Andrei AlexandRescu proposed a solution called Phoenix Singleton (taken from Phoenix Nirvanji)

/ * * 四 * /

Class Singleton

{

PUBLIC:

Static Singleton & Instance () {

IF (! m_pinstatnce) {

LOCK (M_Mutex)

IF (! M_pinstance) {

IF (m_destroyed)

ONDEADRECERENCE ();

Else

CREATE ();

}

UNLOCK (M_Mutex);

}

Return * m_pinstance;

}

Private:

Static Volatitle Singleton * m_pinstatnce;

Static bool m_destroyed;

Private:

Singleton ();

Singleton (Const Singleton &);

Singleton & Operator = (const singleton);

~ Singleton () {

m_pinstance = 0;

m_destroyed = true;

}

Static void create () {

Static Singleton Sinstance;

M_Pinstanace = & SINSTANCE;

}

Static void ONDEADRECE () {

CREATE ();

New (m_pinstance) singleton;

Atexit (KillPhoenixsingleton);

m_destroyed = false;

}

Void killphoenixsingleton () {

M_Pinstance-> ~ Singleton ();

}

}

Singleton * Singleton: m_pinstatnce = null;

BOOL M_DESTROYED = FALSE;

Note that the usage of the new operator used in OndeadReference (): is a so-called Placement New action, which does not assign memory, but constructed a new object on an address.

This is one of the DEAD Reference methods. If the Keyboard or Display object also needs to handle the DEAD Reference problem, then the ondeadreference above will be frequently called, and the efficiency will be low. That is, this problem is: a solution that needs to be provided, the establishment of the object can be provided, and the principle of "first creation will be destroyed" and should specify a destruction order.

Smart Andrei AlexandRescu proposes a "life-lifted Singleton" solution. The idea of ​​this program is: uses atExit () characteristics; after each object is created, put the object into a list (the chain is trained in destruction), and simultaneously calls atexit () registration Destroy function; the destruction function is destroyed from the list of objects that need to be destroyed from the list. (The lazy disease has made L. The implementation of this model, please see the official itself, you can refer to "C design new thinking" book, Andrei Alexandrescu. Everyone looks at the official, after reading this article, do you feel that Singleton is simple? J

转载请注明原文地址:https://www.9cbs.com/read-1052.html

New Post(0)