2009-04-07 4 views
9

Sto cercando di utilizzare un singleton in un servizio Win con multithreading per eseguire la registrazione e volevo sapere quali sono alcuni dei problemi che potrei incontrare. Ho già impostato l'istanza get per gestire la sincronizzazione conQuali sono i pericoli dell'utilizzo di Singleton in un'applicazione multithreading

private static volatile Logging _instance; 
    private static object _syncRoot = new object(); 

    private Logging(){} 
    public static Logging Instance 
    { 
     get 
     { 
      if (_instance==null) 
      { 
       lock(_syncRoot) 
       { 
        if (_instance == null) 
        { 
         _instance = new Logging(); 
        } 
       } 
      } 
      return _instance; 
     } 
    } 

C'è qualcos'altro di cui potrei aver bisogno di preoccuparmi?

+1

Ecco i draghi! Corri finchè puoi. – Samuel

+1

"Non intromettersi negli affari del drago; perché sei croccante e buon gusto con il ketchup. " –

risposta

13

Mi sembra abbastanza buono.

Vedere Implementing the Singleton Pattern in C# per ulteriori informazioni.

Modifica: Probabilmente dovrebbe inserire il ritorno all'interno del blocco, però.

+1

+1 per un buon link –

+0

e blocca prima di confrontare l'istanza con null. –

+0

@Joel Davvero? Non ci avevo pensato ... –

0

Penso che se i metodi di istanza di Logging sono thread-safe non c'è nulla di cui preoccuparsi.

3

Singleton ha il potenziale per diventare un collo di bottiglia per l'accesso alla risorsa incorporata dalla classe e forzare l'accesso sequenziale a una risorsa che potrebbe altrimenti essere utilizzata in parallelo.

In questo caso, potrebbe non essere una cosa negativa, perché non desideri che più elementi vengano scritti nel tuo file nello stesso istante, e anche così non penso che la tua implementazione abbia quel risultato. Ma è qualcosa di cui essere consapevole.

+0

Preferisco il collo di bottiglia e poi l'arresto anomalo, che è quello che stava succedendo quando ho avuto molta attività che è la ragione per cui sto guardando utilizzando un singleton. +1 per una buona intuizione –

1

Si sta utilizzando double-checked locking ciò che è considerato un anti-modello. Wikipedia ha schemi con e senza inizializzazione pigra per lingue diverse.

Dopo aver creato l'istanza di singleton, è necessario assicurarsi che tutti i metodi siano sicuri per i thread.

12

Questo è più informativo di qualsiasi altra cosa.

Quello che hai postato è il ricontrollato algoritmo bloccaggio - e quello che hai postato volontà lavoro, per quanto ne sono a conoscenza. (A partire da Java 1.5 funziona anche lì.) Tuttavia, è molto fragile - se si riesce a sbagliare, si potrebbero introdurre condizioni di gara molto sottili.

io di solito preferisco inizializzare il Singleton nel inizializzatore statico: (. Aggiungere un costruttore statico, se si desidera un po 'di pigrizia in più)

public class Singleton 
{ 
    private static readonly Singleton instance = new Singleton(); 

    public static Singleton Instance 
    { 
     get { return instance; } 
    } 

    private Singleton() 
    { 
     // Do stuff 
    } 
} 

che è più facile pattern per ottenere il diritto, e nella maggior parte dei casi lo fa altrettanto bene.

C'è più dettagli sul mio C# singleton implementation page (collegato anche da Michael).

Per quanto riguarda i pericoli, direi che il problema più grande è che si perde la testabilità. Probabilmente no non valido per la registrazione.

+0

il link al tuo articolo è rotto. –

+0

Questo è abbastanza triste, non è vero? Tali sono i pericoli del postare con un raffreddore puzzolente. Risolto, grazie per aver notato. –

+0

Qual è il motivo dell'utilizzo della proprietà qui? Non è abbastanza sicuro usare il campo pubblico statico di sola lettura? –

1

Un suggerimento migliore sarebbe quello di stabilire il logger in una fase di installazione a thread singolo, quindi è garantito essere lì quando ne hai bisogno. In un servizio di Windows, OnStart è un ottimo posto per farlo.

Un'altra opzione è utilizzare System.Threading.Interlocked.CompareExchange (T%, T, T): metodo T per uscire. È meno confuso ed è garantito che funzioni.

System.Threading.Interlocked.CompareExchange<Logging>(_instance, null, new Logging()); 
+0

Non sono un esperto di C# ma mi aspetto che questo generi una nuova istanza di registrazione su ogni chiamata. La parte 'new Logging()' viene eseguita prima del controllo atomico all'interno di InterlockedCompareExchange. –

+0

Hai ragione. Quanto male sarebbe in realtà dipende dalla semantica del costruttore di Logging (e degli inizializzatori). Ritengo che funzioni ancora, e il primo suggerimento è migliore. –

2

è necessario assicurarsi che ogni metodo nel registratore sono sicuro eseguire contemporaneamente, cioè che non scrivono allo stato condivisa senza il bloccaggio.

+0

Non utilizzare un singleton impedisce di eseguirli contemporaneamente? Pensavo che fosse questo il punto. –

+0

No, più thread possono ancora accedere all'istanza di Logging singola. I suoi metodi * hanno bisogno * di essere thread-safe. +1 per aver portato questo. – Lucas

+0

@bob: il blocco a doppio controllo impedisce la creazione di più di un'istanza (per garantire singleton-ness), non impedisce l'accesso simultaneo da più thread. – Lucas