No es el patrón singleton en su memoria, pero el grado de aplicación es mejor

Inserte la descripción de la imagen aquí

Trama

Tengo un buen amigo Guangjun. Para experimentar la vida, abrió una tienda al lado de la escuela y abrió un restaurante de hamburguesas con té con leche.
Cuando una tienda está recién abierta, lo primero que debe hacer es registrarse en la Oficina Industrial y Comercial y luego hacer un capítulo.

Cuando llegó a la Oficina de Industria y Comercio, le recordaron amistosamente: XXX es solo un archivo privado, por favor no juegue con los demás, usted será responsable de lo sucedido.

Después de registrarse, hacer un capítulo, e incluso abrir una tienda, comenzó a convertirse en gerente de tienda. Al principio había muchas cosas. Tenía que reclutar, comprar, promocionar, calcular cuentas ...
Pero él solo puede hacer estas cosas, personalmente, y ayudar primero a la tienda.

Modo singleton

Entonces, esta historia encaja bien con el escenario de aplicación del modo singleton, por lo que mi amigo quiere hablar con usted sobre el modo singleton.

¿Qué es el patrón singleton?
En el proyecto, algunas clases deben ser "planificadas por la familia", es decir, esta clase solo puede tener una instancia, si hay varias instancias, existe el riesgo de inconsistencia de datos.
Dijiste que si abro una tienda, si hay dos dueños, entonces otro pedido hoy, dije que firmen y él les dijo a los demás que no firmen; este empleado no está activo, dije que abriera, no puede decir que abriera ... ¿No desordenado?

Modo singleton: asegúrese de que una clase tenga solo una instancia y proporcione un punto de acceso global para acceder a ella.

Casualmente, este patrón tiene solo una clase, llamada clase singleton, por lo que no dibujaré el diagrama de clases.

Ejemplos de escenarios de aplicación del modo singleton: cuando hay problemas de datos, la base de datos es la primera en sufrir la peor parte y, naturalmente, la caché no se ejecutará.

Implementación de código singleton

//这里是.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;
}


Impulsar parte

Modo singleton bajo multihilo

Solía ​​haber una base de datos genuina frente a mí, pero desafortunadamente no la apreciaba. Hasta que mi proyecto fallaba repetidamente, no sabía que si podía reiniciarlo, agregaría un bloqueo. . .

Adelante, cuenta las figuras románticas y mira el presente.

Reexaminemos el siguiente código:

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

Si en el caso del subproceso múltiple, una vez que dos subprocesos ingresan 2 al mismo tiempo, ¿qué debo hacer? ¿No es esto bastante normal? No hay ninguna precaución, ¿no es esto un acto de dar cabezas?
¡Para nada! !

Entonces, cámbialo:

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

¿Esta bien? ¿Hay algún amigo que conozca a los cerdos con una idea para llamar "1" en la sección de comentarios a continuación?

Si está escrito de esta manera, debe realizar una operación de bloqueo antes de usar la base de datos, aunque es seguro, aumenta considerablemente la carga.

Entonces, cámbialo de nuevo:

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

Al ver esto, algunos amigos pueden preguntarse: ¿No se puede hacer simplemente cambiando el juicio if y la posición de bloqueo arriba? ¿Por qué agregar otra capa en el exterior? ¿No es innecesario?

Todavía existe el problema:
si tienes dos hilos y rompes la defensa de la primera capa de if, un hilo se atascará fuera del candado a tiempo, pero el candado solo bloquea la parte que crea el singleton. Cuando se obtiene el candado Cuando el hilo libera el bloqueo, otro hilo aún no puede obtener el bloqueo y crear su "singleton" ¿Cuál es el significado de este bloqueo?

Una capa de juicio si se agrega a la cerradura dentro y fuera de la cerradura. Cuando el primer hilo ingresa al espacio de la cerradura y se crea el singleton, los subprocesos subsiguientes no ejecutarán el paso de creación del singleton incluso si obtienen el bloqueo.

Este es un buen modo singleton, que es el "modo perezoso" en el modo singleton.

Chino hambriento

Hay un hombre perezoso y también hay un hombre hambriento.

¿Qué es el estilo chino hambriento? La clave del modelo del hombre hambriento: la inicialización es la instanciación

Ajuste el código anterior:

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

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

En general, la desventaja causada por la carga de estilo hambriento es que no quiero usar la instancia, pero la instancia se ha construido. En comparación con el uso de estilo perezoso, la construcción provocará una pérdida de memoria, pero su implementación es muy simple, sin bloqueo artificial para garantizar la seguridad de los subprocesos. .

¿Perezoso o hambriento?

Cuál elegir depende de las preferencias personales, aquí hay algunas sugerencias:

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

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

Ventajas y desventajas del modo singleton

ventaja

  • Debido a que solo hay un objeto en la memoria en el modo singleton, el costo de la memoria se reduce, especialmente cuando el objeto debe crearse y destruirse con frecuencia, y el rendimiento no se puede optimizar durante la creación o destrucción. La ventaja del modo singleton es muy obvia.
  • El modo singleton puede evitar la ocupación múltiple de la memoria.
  • El modo Singleton puede establecer puntos de acceso globales en el sistema para optimizar y compartir el acceso a los recursos. A menudo uso este truco, y me gusta mucho, porque es realmente conveniente, hacer una clase de bandera singleton, responsable del procesamiento de mapeo de todas las tablas de datos. (Para entender, puedes confiar en mí en privado)

Desventaja

  • El modo singleton generalmente no tiene interfaz y es difícil de expandir. Si desea expandirse, considere la posibilidad de refactorizar.
  • El modo singleton no es bueno para realizar pruebas. En un entorno concurrente, si el singleton no se completa, no se puede probar.

Bueno.

No es fácil de crear, es una buena costumbre recopilarlo fácilmente.

Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/qq_43762191/article/details/108559834
Recomendado
Clasificación