Not the singleton pattern in your memory, but the degree of application is better

Insert picture description here

Story line

I have a good friend Guangjun. In order to experience life, he set up a shop next to the school and opened a milk tea burger restaurant.
When a store is newly opened, the first thing to do is to register with the Industrial and Commercial Bureau, and then make a chapter.

When he arrived at the Bureau of Industry and Commerce, they gave him a friendly reminder: XXX is only a private file, please don't play around with others, you will be responsible for what happened.

After registering, making a chapter, and even opening a store, he started to become a store manager. At the beginning, there were a lot of things. He had to recruit, purchase, promote, and calculate accounts...
But he can only do these things, personally, and help the shop up first.

Singleton mode

Then this story fits well with the application scenario of singleton mode, so my friend wants to talk about singleton mode with you.

What is the singleton pattern?
In the project, some classes need to be "family planned", that is, this class can only have one instance, if there are multiple instances, there is a risk of data inconsistency.
You said that if I open a store, if there are two owners, then another order today, I said to sign, and he told others not to sign; this employee is not active, I said to open, he can’t say to open... Not messy?

Singleton mode: Ensure that a class has only one instance, and provide a global access point to access it.

Coincidentally, this pattern has only one class, called the singleton class, so I won't draw the class diagram.

Examples of application scenarios of singleton mode: When data problems are involved, the database is the first to bear the brunt, and the cache will naturally not run.

Singleton code implementation

//这里是.h文件
//老板类单例
class Single_Boss
{
    
    
public:
    static Single_Boss *instence();//获取数据库单例
//重点在这个函数
	void run();
private:
    Single_Boss();
    ~Single_Boss();
    char *errmsg;

    static Single_Boss *Boss;//实例
};
//源文件

Single_Boss *Single_Boss::Boss= NULL;

Single_Boss::Single_Boss()
{
    
    
    cout << "Big Boss" << endl;	//debug
}

Single_Boss::~Single_Boss()
{
    
    
    cout<<"Seeyou Boss"<<endl;
}

Single_Boss* Single_Boss::instence()
{
    
    
    if(!Boss)
    {
    
    
        Boss= new Single_Boss();
    }
    	return Boss;
}

void Single_Boss::run(){
    
    
	cout<<"你好,欢迎光临XXX,请问需要点什么服务?"<<endl;
}

int main()
{
    
    
	//Single_Boss *boss = new Single_Boss();	//不信的话大可以将这一行放出来,下面那行屏蔽掉试试
    Single_Boss *boss= Single_Boss::instence();	//这是在类外使用单例
    
    boss->run();
    
    return 0;
}


Boost part

Singleton mode under multithreading

There used to be a genuine database in front of me, but unfortunately I didn't cherish it. Until my project crashed repeatedly, I didn't know that if I could restart it, I would add a lock. . .

Go ahead, count the romantic figures, and look at the present.

Let's re-examine the following code:

Single_Boss* Single_Boss::instence()	//1
{
    
    										
    if(!Boss)							//2
    {
    
    									
        Boss= new Single_Boss();		//3
    }									
    return Boss;						
}										

If in the case of multithreading, once two threads enter 2 at the same time, what should I do? Isn't this quite normal? There is no precaution at all. Isn't this an act of giving someone a head?
For nothing! !

So, change it:

Single_Boss* Single_Boss::instence()	//1
{
    
    					
	lock(db_mutex);	//假设这个锁我已经初始化过了					
    if(!Boss)							//2
    {
    
    									
        Boss= new Single_Boss();		//3
    }				
    unlock(db_mutex);	//上锁和解锁一定要同时写,就算忘记写中间步骤,也要先写解锁					
    
    return Boss;						
}	

Is this okay? Is there any friend who knows pigs with insight to call "1" in the comment section below?

If written in this way, you must perform a lock operation before using the database. Although it is safe, it greatly increases the load.

So, change it again:

Single_Boss* Single_Boss::instence()	//1
{
    
    				
	if(!Boss){
    
    			//一重锁定
		lock(db_mutex);				
	    if(!Boss)		//二重锁定				
	    {
    
    									
	        Boss= new Single_Boss();		
	    }				
	    unlock(db_mutex);	//上锁和解锁一定要同时写,就算忘记写中间步骤,也要先写解锁					
    }
    return Boss;						
}

Seeing this, some friends may wonder: Can’t it be done by simply changing the if judgment and the lock position above? Why add another layer on the outside? Isn’t it unnecessary?

There is still the problem:
if you have two threads and break through the defense of the first layer of if, one thread will be stuck outside the lock in time, but the lock only locks the part that creates the singleton. When the lock is obtained When the thread releases the lock, another thread can not still obtain the lock and create its "singleton". What is the significance of this lock?

A layer of if judgment is added to the lock inside and outside the lock. When the first thread enters the lock space and the singleton is created, the subsequent threads will not execute the singleton creation step even if they get the lock.

This is a good singleton mode, which is the "lazy man mode" in the singleton mode.

Hungry Chinese

There is a lazy man, and there is also a hungry man.

What is the hungry Chinese style? The key to the hungry man model: initialization is instantiation

Fine-tune the code above:

Single_Boss *Single_Boss::Boss= new Single_Boss();

Single_Boss* Single_Boss::instence()
{
    
    
//不需要进行实例化
    //if(!Boss)
    //{
    
    
    //    Boss= new Single_Boss();
    //}
   	return Boss;
}

Generally, the disadvantage caused by the hungry-style loading is that I don’t want to use the instance but the instance has been constructed. Compared with the lazy-style use, the construction will cause a waste of memory, but its implementation is very simple, without artificial locking to ensure thread safety .

Lazy or hungry?

Which one to choose depends on personal preference, here are some suggestions:

懒汉:在访问量较小时,采用懒汉实现。这是以时间换空间。

饿汉:由于要进行线程同步,所以在访问量比较大,或者可能访问的线程比较多时,采用饿汉实现,可以实现更好的性能。这是以空间换时间。

Advantages and disadvantages of singleton mode

advantage

  • Because there is only one object in the memory in the singleton mode, the memory cost is reduced, especially when the object needs to be created and destroyed frequently, and the performance cannot be optimized during creation or destruction. The advantage of the singleton mode is very obvious.
  • Singleton mode can avoid multiple occupation of memory.
  • Singleton mode can set global access points in the system to optimize and share resource access. I often use this trick, and I like it very much, because it is really convenient, to make a flag singleton class, responsible for the mapping processing of all data tables. (To understand, you can privately trust me)

Disadvantage

  • The singleton mode generally has no interface and is difficult to expand. If you want to expand, consider refactoring.
  • Singleton mode is not good for testing. In a concurrent environment, if the singleton is not completed, it cannot be tested.

Okay.

It's not easy to create. It's a good habit to collect it easily.

Insert picture description here

Guess you like

Origin blog.csdn.net/qq_43762191/article/details/108559834