1 A single case pattern in a textbook
We all know how a simple singleton pattern can be implemented: the constructor is declared private or protect to prevent being instantiated by an external function, and the internal holding of a private static class pointer holds a unique instance, and the action of the instance is performed by a public class method. The method also returns the unique instance of the Singleton class.
Code on:
Class Singleton
{
protected:
singleton () {}
private:
static singleton* p;
Public:
static singleton* instance ();
singleton* Singleton::p = NULL;
singleton* singleton::instance ()
{
if (p = = NULL)
p = new Singleton ();
return p;
}
This is a great implementation, easy to understand. But is this a perfect implementation? No! The method is thread insecure, considering that two threads first call the instance method at the same time and that p is a null value, then two threads construct an instance to P, which is a serious error! At the same time, this is not a single case of the only implementation!
2 loafers and a hungry man
There are about two ways to implement a single example: lazy and a hungry man.
lazy: Hence the name of righteousness, not to the last resort to instantiate the class, that is, the first time to use the class instance will be instantiated, so the top of the classic method is classified as lazy implementation;
a hungry man: you must be hungry. So it is instantiated when the Singleton class is defined.
Features and selection:
Because of the thread synchronization, it is possible to achieve better performance with a a hungry man implementation when there is a large number of accesses, or if the threads are more likely to be accessed. This is to change time in space.
When the amount of traffic is small, use lazy to achieve. It's time to change space.
3 Thread-Safe lazy implementations
Thread is not safe, how to do? The most intuitive way: add locks.
Method 1: Lock the classic lazy implementation:
Class Singleton
{
protected:
Singleton ()
{
pthread_mutex_init (&mutex);
}
Private:
static singleton* p;
Public:
static pthread_mutex_t mutex;
Static singleton* initance ();
pthread_mutex_t Singleton::mutex;
singleton* Singleton::p = NULL;
singleton* singleton::initance ()
{
if (p = = NULL)
{
pthread_mutex_lock (&mutex);
if (p = = NULL)
p = new Singleton ();
Pthread_mutex_unlock (&mutex);
}
return p;
}
Method 2: Lazy implementation of internal static variables
This method is also easy to implement, to define a static instance in the instance function, or to have a unique instance, which only needs to return its pointer. It is really easy to recommend this implementation.
Class Singleton
{
protected:
Singleton ()
{
pthread_mutex_init (&mutex);
}
Public:
static pthread_mutex_t mutex;
Static singleton* initance ();
int A;
};
pthread_mutex_t Singleton::mutex;
singleton* singleton::initance ()
{
pthread_mutex_lock (&mutex);
static Singleton obj;
Pthread_mutex_unlock (&mutex);
Return &obj;
}
4 A Hungry man implementation
Why don't I say "thread-safe a hungry man implementation"? Because the A hungry man implementation is inherently thread-safe, without locking. Why? Think for yourself!
Class Singleton
{
protected:
Singleton ()
{}
private:
static singleton* p;
Public:
static singleton* initance ();
singleton* Singleton::p = new Singleton;
singleton* singleton::initance ()
{return
p;
}
Is it particularly simple?
Do you think it is easy to change time in space?
How do I write a thread-safe single case pattern during an interview? Sure how simple how to write Ah! A hungry man mode instead of the most lazy [serious face]!
The above is a small series for everyone to bring the cliché of C + + single case mode and thread safety single case mode (lazy/a hungry man) all content, I hope that we support cloud-Habitat Community ~