Pregunta

Existe este objeto similar a una conexión DB que necesitará mi aplicación web. Es bastante lento de crear y se usará en raras ocasiones, por lo que me gustaría mantener solo una sola instancia. Si varias solicitudes lo necesitan al mismo tiempo, lock() el objeto y serializarán su acceso.

Para hacer las cosas más divertidas, el objeto es desechable y se puede cerrar. Naturalmente, evitaré escribir código que lo cierre, pero ... ya sabes ... más vale prevenir que curar, ¿verdad?

Entonces, el enfoque na & # 239; cinco sería implementarlo de la siguiente manera:

private static DBClass _Instance;
private static object _DBLock = new object();

public DBClass GetDB()
{
    if ( _Instance == null )
        lock (_DBLock )
            if ( _Instance == null )
                _Instance = CreateInstance();
    lock (_Instance)
        if ( _Instance.Disposed )
            _Instance = CreateInstance();
    return _Instance;
}

Luego se usará como:

lock (var Conn = Global.GetDB() )
{
    // Use Conn here.
}

Esto probablemente funcionará la mayor parte del tiempo, pero veo una apertura que podría ser explotada: si dos hilos llaman a esto al mismo tiempo, obtienen la misma instancia al mismo tiempo, y entonces uno podría Dispose() antes de que el otro adquiera un Disposed sobre él. Por lo tanto, el código posterior falla. Verificar <=> en cada lugar que lo usa también parece incómodo. De hecho, <=> también parece incómodo, pero la instancia no es inherentemente segura para subprocesos, por lo que no hay nada que pueda hacer al respecto.

¿Cómo implementaría esto?

¿Fue útil?

Solución

Para empezar, sugiero evitar el bloqueo de doble verificación. Es muy fácil equivocarse, como lo ha hecho en este caso, al no hacer que la variable sea volátil.

Dado que no quiere realmente deshacerse del objeto, ¿hay alguna razón para no envolverlo en algo que implemente la misma API pero sin exponer la eliminación? De esa manera, también podría encapsular el bloqueo, potencialmente, dependiendo de cómo use realmente el objeto. Otra forma de hacerlo sería exponer una API en términos de Action<DBClass>: pasa la acción que desea realizar con el objeto y el asistente se encarga de crear la instancia y bloquearla adecuadamente.

Un punto final: todo esto se siente algo complicado en términos de comprobabilidad. No sé si eres fanático de las pruebas unitarias, etc., pero los singletons a menudo hacen la vida algo incómoda para las pruebas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top