当前位置:网站首页>Creative mode 1 - single case mode
Creative mode 1 - single case mode
2022-07-05 23:13:00 【Dutkig】
After learning C++ Knowledge about static members of , Let's first understand the simplest design pattern : The singleton pattern .
The motivation of the singleton model
For some classes of a software system , There is no need to create multiple instantiated objects , Like Windows System task manager or recycle bin , No matter how many times we click, only one window will pop up , Because if multiple windows pop up , It's actually a repeating object , It is bound to waste system resources , Therefore, we need to ensure that there is only one instance of a class in the system , When this instance is created successfully , We can no longer create other objects of the same type , All operations can only be based on this unique instance , For example, ensure the uniqueness of objects , We propose a singleton pattern .
From the perspective of concrete implementation :
- Singleton mode only provides private constructors ;
- The class definition contains a static private object of the class ;
- This class provides a static common function to create or obtain its own static private object .
1、 The hungry man mode
An example of the hungry man model is The main function has been generated before it runs ( This is because the initialization of static data members is completed before the main function runs ), Because it's hungry , Very anxious .^ _ ^…
class Object
{
private:
int value;
static Object instance;
private:
Object(int x = 0):value(x){
}// Objects cannot be built outside anywhere else
Object(const Object & obj) = delete;// Prevent copying construction objects
Object & operator=(const Object & obj) = delete;// Prevent building objects through assignment statements
public:
static Object & GetInstance()// If you do not return by reference here, you will transfer the copy structure as a transition
{
// But our copy structure has been deleted , Unable to complete . Another solution is to return with a pointer
return instance;
}
};
// Static member initialization
Object Object::instance();
int main()
{
Object & obja = Object::GetInstance();
Object & objb = obja.GetInstance();
cout<<&obja<<endl;
cout<<&objb<<endl;
}
We can see ,obja and objb All represent the same object :
Be careful
: The above way Objects created : yes Thread safety
Of , When two threads modify it respectively , It's not thread safe .
such as : Put the following two functions into two threads
void funa()
{
Object & obja = Object::GetInstance();
cout<<&obja<<endl;
}
void funb()
{
Object & objb = Object::GetInstance();
cout<<&objb<<endl;
}
#include<thread>
int main()
{
thread thra(funa);
thread thrb(funb);
thra.join();
thrb.join();
return 0;
}
No matter how many threads call , When building objects, we all get unique instantiated objects
summary :
experience : Why should we define this design pattern as hungry man singleton pattern ?
namely : Like a hungry man , Create instances whether you need them or not , That is, create a good instance when the class is generated , This is a practice of exchanging space for time . As a hungry man , Embodies its essence ——“ All I want ”.
- advantage : Instantiate when the program is loaded , After that, the operation efficiency will be higher
- shortcoming : Because the program is instantiated when it is loaded , If there is no further operation on this class , Will lead to a waste of memory .
Lazy singleton mode
An example of lazy mode is lazy , So only when someone wants to use an instance new, Have to build .
class Object
{
private:
int value;
static Object *pobj;
private:
Object(int x = 0):value(x){
}
Object(const Object & obj) = delete;
Object & operator=(const Object & obj) = delete;
public:
static Object * GetInstance()
{
if(pobj == nullptr)
{
pobj = new Object();
}
return pobj;
}
};
// Static member initialization
Object* Object::pobj = nullptr;
void funa()
{
Object * pobja = Object::GetInstance();
cout<<pobja<<endl;
}
void funb()
{
Object * pobjb = Object::GetInstance();
cout<<pobjb<<endl;
}
int main()
{
thread thra(funa);
thread thrb(funb);
thra.join();
thrb.join();
return 0;
}
In our opinion, even if the running result is ok , But this code is actually thread unsafe .
Because there have been many object constructions , This is inconsistent with the original principle of the simple interest single case model
Explain in detail :
In a single thread , This kind of writing can be used correctly , But not in multithreading , This method is thread unsafe .
(1) If a thread A And thread B, These two threads need to access getInstance function , Threads A Get into getInstance function , And detect if Conditions , Because it is the first time to enter ,value_ It's empty ,if Conditions established , Ready to create an object instance .
(2) however , Threads A It's possible to be OS The scheduler of is interrupted and sleep is suspended , And give control to the thread B.
(3) Threads B Also came to if Conditions , Find out value_ Still for NULL, Because the thread A It was interrupted before it could be constructed . At this point, suppose the thread B Finished creating the object , And return smoothly .
(4) After that thread A Awakened , Carry on new Create the object again , thus , Two threads build two object instances , This destroys uniqueness .
in addition , There are also memory leaks ,new What comes out has never been released
So how to solve this problem ??—— Join in Thread mutex
#include<mutex>
std::mutex mtx;// Build a lock object
class Object
{
private:
int value;
static Object* pobj;
private:
Object(int x = 0) :value(x) {
}
Object(const Object& obj) = delete;
Object& operator=(const Object& obj) = delete;
public:
static Object* GetInstance()
{
if (pobj == nullptr)
{
lock_guard<std::mutex> lock(mtx);
if (pobj == nullptr)// Judge again , Ensure that multiple threads will not enter at the same time during locking
{
pobj = new Object(10);
}
}
return pobj;
}
};
// Static member initialization
Object* Object::pobj = nullptr;
At this time, we found that : The problem is really solved
Actually , At present, the lazier style is more popular, and the following one is more concise Writing : it Take advantage of static Keyword features
.
class Object
{
private:
int value;
static Object* pobj;
private:
Object(int x = 0) :value(x) {
}
Object(const Object& obj) = delete;
Object& operator=(const Object& obj) = delete;
public:
static Object* GetInstance()
{
static Object instance;
return &instance;
}
};
This is thread safe , Because this instance allocates memory in the global data area , The object is initialized only once when it is created , Go deeper
The explanation is : Compiler for static Initialization of static local variables , It will automatically lock and unlock .
experience : Why should we define this design pattern as lazy singleton pattern ?
namely : Like a lazy man , You need to use the program to create instances , You don't need to create an instance program “ Don't bother ” To create instances , This is a time for space approach , This is reflected. “ Lazy nature ”.
边栏推荐
- LeetCode145. Post order traversal of binary tree (three methods of recursion and iteration)
- Nacos installation and service registration
- C Primer Plus Chapter 9 question 9 POW function
- Déterminer si un arbre binaire est un arbre binaire complet
- Leetcode weekly The 280 game of the week is still difficult for the special game of the week's beauty team ~ simple simulation + hash parity count + sorting simulation traversal
- Go语言实现原理——锁实现原理
- Matlab smooth curve connection scatter diagram
- Activate function and its gradient
- Openresty ngx Lua regular expression
- Go language implementation principle -- map implementation principle
猜你喜欢
audiopolicy
Yiwen gets rid of the garbage collector
一文搞定class的微观结构和指令
There are 14 God note taking methods. Just choose one move to improve your learning and work efficiency by 100 times!
Finally understand what dynamic planning is
Codeforces Global Round 19
From the perspective of quantitative genetics, why do you get the bride price when you get married
February 13, 2022-4-symmetric binary tree
利用LNMP实现wordpress站点搭建
Mathematical formula screenshot recognition artifact mathpix unlimited use tutorial
随机推荐
Common JVM tools and optimization strategies
Go语言实现原理——Map实现原理
Composition of interface
[speech processing] speech signal denoising and denoising based on MATLAB low-pass filter [including Matlab source code 1709]
From the perspective of quantitative genetics, why do you get the bride price when you get married
一文搞定垃圾回收器
【Note17】PECI(Platform Environment Control Interface)
C Primer Plus Chapter 9 question 9 POW function
Practice of concurrent search
Design and implementation of secsha system
CorelDRAW plug-in -- GMS plug-in development -- new project -- macro recording -- VBA editing -- debugging skills -- CDR plug-in (2)
实现反向代理客户端IP透传
[speech processing] speech signal denoising and denoising based on Matlab GUI low-pass filter [including Matlab source code 1708]
Activate function and its gradient
Registration of Electrical Engineering (elementary) examination in 2022 and the latest analysis of Electrical Engineering (elementary)
Using LNMP to build WordPress sites
February 13, 2022-4-symmetric binary tree
Krypton Factor purple book chapter 7 violent solution
东南亚电商指南,卖家如何布局东南亚市场?
一文搞定JVM常见工具和优化策略