12. Modo Singleton del modo de rendimiento del objeto (Sigleton)

 modelo de rendimiento de objetos

  • La orientación a objetos resuelve muy bien el problema "abstracto", pero es inevitable pagar un cierto precio. En términos generales, el costo de la orientación a objetos es en su mayoría insignificante, pero en algunos casos, el costo de la orientación a objetos debe manejarse con cuidado.
  • patrón típico
    • Sigleton
    • peso mosca

-------------------------------------------------- --------------------------------------------

patrón único

1. Motivación

  • En los sistemas de software, a menudo hay clases especiales de este tipo que deben garantizarse para tener solo una instancia en el sistema para garantizar su corrección lógica y buena eficiencia.
  • ¿Cómo eludir los constructores convencionales y proporcionar un mecanismo para garantizar que una clase tenga solo una instancia?
  • Esto debería ser responsabilidad del diseñador de la clase, no del usuario.

2. Código

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. Definición del esquema

Garantiza que solo haya una instancia de una clase y proporciona un punto de acceso global a esa instancia.

                                                                                ---《Patrones de diseño》GOF

4. Estructura

 5. Resumen

  • Los constructores de instancias en el patrón Sigleton se pueden configurar como protegidos para permitir la creación de subclases.
  • El modo Sigleton generalmente no es compatible con el constructor de copia y la interfaz Clone, porque esto puede dar lugar a múltiples instancias de objetos.

Supongo que te gusta

Origin blog.csdn.net/bocai1215/article/details/127561538
Recomendado
Clasificación