object performance model
- Object-oriented solves the "abstract" problem very well, but it is inevitable to pay a certain price. Generally speaking, the cost of object-oriented is mostly negligible, but in some cases, the cost of object-oriented must be handled carefully
- typical pattern
- Sigleton
- Flyweight
----------------------------------------------------------------------------------------------
singleton pattern
1. Motivation
- In software systems, there are often such special classes that must be guaranteed to have only one instance in the system to ensure their logical correctness and good efficiency.
- How to bypass conventional constructors and provide a mechanism to ensure that a class has only one instance?
- This should be the responsibility of the designer of the class, not the user
2. Code
class Sigleton{
private:
Sigleton();
Sigleton(const Sigleton& other);
public:
static Sigleton*getInstance();
static Sigleton* m_instance;
};
Sigleton* Sigleton::m_instance = nullptr;
// 线程非安全版本
Sigleton* Sigleton::getInstance(){
if (m_instance == nullptr){
m_instance = new Sigleton();
}
return m_instance;
}
// 线程安全,但锁的代价过高
Sigleton* Sigleton::getInstance(){
Lock lock;
if (m_instance == nullptr){
m_instance = new Sigleton();
}
return m_instance;
}
// 双检查锁,但由于内存读写reorder不安全
Sigleton* Sigleton::getInstance(){
if (m_instance == nullptr){
Lock lock;
if (m_instance == nullptr){
// 下面New的大概步骤
// Step1. 先分配内存
// Step2. 调用Sigleton构造器,对刚才分配的内存进行初始化
// Step3. 将刚才分配的地址赋值给m_instance
// 但是在CPU指令级别,上面的步骤有可能会被reorder
// 编译器优化后,有可能会变成:
// Step1 -> Step3 -> Step2
// 如果此时执行到Step3,切换到另外一个线程,最外面的判断将是非空,然后直接去使用这个还没有构造的m_instance,导致错误
m_instance = new Sigleton(); // 2000年左右才被一个java领域的专家发现这个BUG
}
}
return m_instance;
}
// C++11版本之后的跨平台版本
std::atomic<Sigleton*> Sigleton::m_instance = nullptr;
std::mutex Sigleton::m_mutex;
Sigleton* Sigleton::getInstance(){
Sigleton* tmp = m_instance.load(std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_acquire); // 获取内存fence
if (tmp == nullptr){
std::lock_guard<std::mutex> lock(m_mutex);
tmp = m_instance.load(std::memory_order_relaxed);
if (tmp == nullptr){
tmp = new Sigleton();
std::atomic_thread_fence(std::memory_order_relaxed); // 释放内存fence
m_instance.store(tmp, std::memory_order_relaxed);
}
}
return tmp;
}
3. Schema definition
Ensures that there is only one instance of a class and provides a global access point to that instance.
---《Design Patterns》GOF
4. Structure
5. Summary
- Instance constructors in the Sigleton pattern can be set to protected to allow subclassing.
- Sigleton mode generally does not support copy constructor and Clone interface, because this may result in multiple object instances