In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article mainly introduces "what is the method of Singleton pattern creation, multithreading and destruction". In daily operation, I believe that many people have doubts about the method of Singleton pattern creation, multithreading and destruction. Xiaobian consulted all kinds of materials and sorted out simple and easy-to-use methods of operation. I hope it will be helpful to answer the doubts of "what is the method of Singleton pattern creation, multithreading and destruction?" Next, please follow the editor to study!
1 Singleton creation
1.1 GOF Singleton
The implementation of the Singleton pattern in GOF works is as follows:
/ * Jie one * / class Singleton {public: static Singleton * Instance () {/ / 1 if (! m_pInstatnce) / / 2 m_pInstance = new Singleton;//3 return mroompInstance; / / 4} private: static Singleton * massipInstatnce; / / 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 generate an object of Singleton only when we need to call it. The benefit of this is that it is a very good strategy if the result produced by the object is expensive but not often used. But if the Instance is called frequently, then some people think that the judgment in Instance is inefficient (although it is only a judgment statement ^ _ ^), then we should put the fifth statement as
Static Singleton m_Instatnce
In this way, it is more efficient to return & m_Instance directly from Instatnce without making any judgment. (isn't it? )
After this modification, we will have disastrous consequences:
1: first of all, it is possible that the compiler will not be able to pass this pass, saying that the external variable m_Instance cannot be solved (visural Category 6.0)
Error LNK2001: unresolved external symbol "private: static class Singleton Singleton::m_Instance" (m_Instance@Singleton@@0V1@A)
2: will it be all right if the compiler passes this pass? The answer is no.
* the static variable object is generated when the compiler compiles regardless of whether Instance is used or not, that is, resource consumption is inevitable.
The second is that there is no guarantee that the compiler will initialize m_Instance first. So it is possible for the call to Instance to return a Singleton object that has not yet been constructed. This also means that you cannot guarantee that the m_Instance used by any external object is a properly initialized object.
1.2 Meyers Singleton
How can we solve this problem? it's actually very simple. A very elegant approach was proposed by Scott Meyers***, so it is also called Meyers Singleton. It relies on the magical skills of the compiler. That is, the static object within the function is initialized only when the function is executed for * times (note that it is not a static constant).
/ * solution II * / class Singleton {public: static Singleton * Instance () {/ / 1 static Singleton sInstance; / / 2 return & sInstance; / / 3} private: Singleton (); / / 4 Singleton (const Singleton&) / / 5 Singleton& operator= (const Singleton&); / / 6 ~ Singleton (); / / 7}
Solution 2 defines a Singleton object of Static in Instance to solve the problem of initialization in Instance, and also solves the problem of defining Static member object smoothly.
Note that if solution 2 cannot be compiled in VC6, 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 declaration of 'Singleton::~Singleton'
What is the wrong cause of the problem (please think carefully ^ _ ^)
The reason is that after the static Singleton object is generated, the compiler automatically generates a destroy function _ _ DestroySingleton, then calls atexit () to register and executes _ _ DestroySingleton when the program exits. However, because the destructor of Singleton is private, an access error is generated. (the BUG should be modified in a later compiler)
1.3 Singleton improvement
Let Instance return the reference (reference). If the pointer is returned, the caller may call it delete.
1.4 points for attention of Singleton
In the above solution, please pay attention to the benefits of dealing with constructors and destructors (please understand that I am lazy again).
2 multithreading
In solution 1, if we run in a multithreaded environment, is the solution * *? what will be the consequences?
The result is a memory leak, and it is possible to get different Singleton objects before and after (think for yourself, there will be an answer later).
To solve this problem, change the Instance of Jieyi to the following:
Singleton& Singleton::Instance () {Lock (m_mutex); / / means to obtain mutexes / / 1 If (! m_pInstance) {/ / 2 m_pInstance = new Singleton; / / 3} UnLock (m_mutex); / / 4 return * m_pInstance / / 5}
This approach will solve the problem of memory leaks running in a multithreaded environment, but the result is that when the m_mutex is locked, other threads trying to lock the m_mutex will have to wait. And each time the lock operation is performed at a high price, that is, the solution to this solution is not attractive.
So let's change the above code to the following way:
Singleton& Singleton::Instance () {If (! m_pInstance) {/ / 1 Lock (m_mutex); / / means to obtain mutexes / / 2 m_pInstance = new Singleton; / / 3 UnLock (m_mutex); / / 4} return * m_pInstance / / 5}
Is there no problem with the result of this modification? NO!!!! The result of this scheme is the same as solution one, and the reason is the same, which will cause memory leakage. At this point, the "double detection lock" mode is on the scene.
The "double detection locking" (Double-Checked Locking) mode is proposed by Doug Schmidt and Tim Harrison to solve the multithread singletons problem.
Singleton& Singleton::Instance () {If (! m_pInstance) {/ / 1 Lock (m_mutex); / / means to obtain mutexes / / 2 If (! m_pInstance) / / 3 m_pInstance = new Singleton; / / 4 UnLock (m_mutex); / / 5} return * m_pInstance / / 6}
Please take a look at the third sentence above. Does this sentence have the power to turn decay into magic?
The above plan is good enough. The answer is still Nostradamus! (do you see if the officer is already depressed? this is not playing with me? Please be patient and listen to me carefully ^ _ ^)
If it is possible for the compiler to optimize the above code on a RISC machine, execute the third sentence before locking the m_mutex. This is entirely possible because the * sentence, like the third sentence, can be handled in this way according to the principle of code optimization. As a result, the "double test lock" that we are proud of did not work (L)
What shall I do? Solve it. How to solve it? Simple, let's just add a modifier in front of m_pInstance. What modifier?.
à volatile (simple)
Then our complete solution is as follows:
/ * solution 3 * / class Singleton {public: static Singleton & Instance () {/ / 1 if (! m_pInstatnce) {/ / 2 Lock (m_mutex) / / 3 If (! m_pInstance) / / 4 m_pInstance = new Singleton;//5 UnLock (m_mutex); / / 6} return * mroompInstance; / / 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 destruction
Here we come to the simplest and most complex part of Singleton.
Why is it simple? We can simply ignore the destruction of the created object m_pInstance. Because although we have not deleted the Singleton object, it will not cause a memory leak. Why do you say that? Because memory leaks occur only when you allocate cumulative row data and lose all reference to him. In the case of Singleton, it is not the case above, there is nothing cumulative, and we still have references to it until the end. In modern operating systems, when a process ends, all memory space for that process is automatically freed. (refer to "effective C++" Section 10, which describes memory leaks).
But sometimes leaks still exist. What is that? It's a resource leak. For example, if the Singleton object manages network connections, OS mutexes, handles of process communication, and so on. At this point, we must consider the destruction of Singleton. When it comes to destruction, it's a complicated subject (I can't finish it for two days and three nights). It's a joke, everybody relax.
We need to delete the Singleton object at the right place and at the right time, and also create or recreate the Singleton object at the right time.
In our solution II, the destructor of Singleton is automatically called at the end of the program, and the acquired resources are automatically released. In most cases, it works effectively. What are the special circumstances?
We take the KDL (keyboard,display,log) model as an example, in which KMagazine uses the Singleton pattern. Whenever there is an exception in keyboard or display, we must call log to write it to the log, otherwise the log object should not be created. For the latter, our Singleton can be satisfied when it is created.
As we mentioned earlier, when an object is generated (instead of an object generated by new), the compiler automatically calls the atexit (_ _ DestroyObject) function to implement the object's destructing operation. On the other hand, the C++ object is destructed by LIFO, that is, the object is generated first and then destroyed.
If the log object is called under normal circumstances, then start destroying the object. According to the principle of "destroy after creation": the log object will be destroyed, and then the display object will be destroyed. At this point, display found an exception during destruction, so the log object was called to record it. But in fact, the log object has been destroyed, so calling the log object will have unintended consequences, which we call Dead Reference. So the previous solution can not solve the problems we have encountered at present.
Andrei Alexandrescu came up with a solution called Phoenix Singleton (from the Phoenix Nirvana allusion)
/ * solution 4 * / class Singleton {public: static Singleton & Instance () {if (! m_pInstatnce) {Lock (m_mutex) If (! m_pInstance) {if (m_destroyed) OnDeadReference (); else Create ();} UnLock (m_mutex);} return * mroompInstance;} private: static volatitle Singleton * massipInstatnce; 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 OnDeadReference () {Create () New (m_pInstance) Singleton; atexit (KillPhoenixSingleton); m_destroyed = false;} void KillPhoenixSingleton () {masked pInstance- > ~ Singleton ();}} Singleton * Singleton:m_pInstatnce = NULL; bool m_destroyed = false
Note the use of the new operator used in OnDeadReference () here: the so-called placement new operation, which does not allocate memory, but instead constructs a new object at an address.
This is one of the solutions to Dead Reference. If the keyboard or display object also needs to deal with the DeadReference problem at this time, then the above OnDeadReference will be called frequently and will be very inefficient. That is, the problem is that the need to provide a solution to deal with the creation of objects can not follow the principle of "create first and destroy", but should specify a destruction order for them.
The clever Andrei Alexandrescu proposed a "Singleton with lifespan" solution. The idea of this scheme is to make use of the characteristics of atexit (); after each creation of an object, put the object into a linked list (the linked list is trained in the order of destruction), and at the same time call atexit () to register a destroy function; the destruction function gets the object that needs to be destroyed most from the linked list to destroy.
At this point, the study on "what is the method of Singleton pattern creation, multithreading and destruction" is over. I hope to be able to solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.