2012-10-10 15 views
8

Mi chiedo quale sia l'approccio migliore per caricare i dati in modo thread-safe. Tradizionalmente, ho usato il modello a doppia serratura e questo ha funzionato abbastanza bene. Ora, con l'aggiunta del tipo System.Lazy, mi chiedo se basarsi sull'interno di Lazy e il caricamento sia migliore e fare il lavoro in un modo molto migliore. Sembra più pulito e più facile da leggere, ma è meglio?C# Threading & Blocking

Qualche idea?

namespace SomeNameSpace 
{ 
    public class DataStoreContext 
    { 
    private readonly static Lazy<DataStoreContext> context = new Lazy<DataStoreContext>(() => new DataStoreContext()); 
    private Lazy<Dictionary<string, Entity>> _entities = new Lazy<Dictionary<string, Entity>>(() => { return DataStoreContext.Instance.Load(); }); 
    private readonly object _syncRoot = new object(); 
    private DataStoreContext() 
    { 
    } 

    public Dictionary<string, Entity> Data 
    { 
     get { return _entities.Value; } 
    } 

    public static DataStoreContext Instance 
    { 
     get { return context.Value; } 
    } 

    private Dictionary<string, Entity> Load() 
    { 
     // Load Data from some data store. 
     return null; 
    } 

    private Dictionary<string, Entity> LoadWithLock() 
    { 
     if (_entities == null) 
     { 
     lock (_syncRoot) 
     { 
      if (_entities == null) 
      { 
      Dictionary<string, Entity> entities = this.Load(); 
      _entities = entities; 
      return _entities; 
      } 
     } 
     } 

     return _entities ; 
    } 

    public void Clear() 
    { 

    _entities = new Lazy<Dictionary<string, Entity>>(() => { return DataStoreContext.Instance.Load(); }); 

    } 
    } 
} 

risposta

3

Per la documentazione di MSDN:

Per impostazione predefinita, tutti i membri pubblici e protetti della classe pigro sono thread-safe e possono essere utilizzati contemporaneamente da più thread. Queste garanzie sulla sicurezza dei thread possono essere rimosse facoltativamente e per istanza, utilizzando parametri per i costruttori del tipo.

È abbastanza sicuro per le operazioni di lettura e scrittura. Pertanto, direi che rimani con questo perché è molto più pulito.

Ma, come afferma la documentazione, è possibile disattivare la sicurezza del thread con alcuni parametri facoltativi per il costruttore.

+0

Ho scoperto che avrei introdotto un errore se non avessi caricato correttamente le entità sull'invocazione di Clear() subito. Più lo guardo, più mi piace. Ho intenzione di iniziare a utilizzare il System. Più pigro. Grazie per l'input. – Sam

+0

@Sam, sono felice di poter essere di aiuto. –

8

Sembra più pulito e più facile da leggere, ma è meglio?

Sì. Il blocco con doppia verifica è difficile da ottenere. Richiede una barriera di memoria per essere corretta. La tua implementazione non è in realtà garantita dal CIL *.

Per dettagli, vedere this Wikipedia entry.

Utilizzando Lazy<T>, si ottiene un codice che non è solo più pulito, ma che è effettivamente corretto su tutte le piattaforme.

* Si noti che questo probabilmente funziona perfettamente su x86 e x64, eseguendo il runtime Microsoft, a causa del modello di memoria della piattaforma. Tuttavia, non è garantito che le specifiche siano corrette senza adeguate barriere di memoria.

+0

Capito. Grazie! – Sam