2009-05-28 13 views
6

In un C# app, supponiamo di avere una sola classe globale che contiene alcuni elementi di configurazione, in questo modo:C sicurezza # filo di impostazioni di configurazione globale

public class Options 
{ 
    int myConfigInt; 
    string myConfigString; 
    ..etc. 
} 

static Options GlobalOptions; 

i membri di questa classe sarà usi attraverso diversi thread:

Thread1: GlobalOptions.myConfigString = blah; 

mentre

Thread2: string thingie = GlobalOptions.myConfigString; 

Utilizzo di una serratura per l'accesso ai GlobalOptions l'oggetto sarebbe anche un blocco non necessario quando 2 thread accedono a membri diversi, ma d'altra parte la creazione di un oggetto di sincronizzazione per ogni membro sembra un po 'esagerata.

Inoltre, l'utilizzo di un blocco sulle opzioni globali renderebbe il mio codice meno piacevole, credo; se devo scrivere

string stringiwanttouse; 
lock(GlobalOptions) 
{ 
    stringiwanttouse = GlobalOptions.myConfigString; 
} 

ovunque (ed è questo thread-safe o è stringiwanttouse ora solo un puntatore a myConfigString? Sì, Sono nuovo di C# ....) invece di

string stringiwanttouse = GlobalOptions.myConfigString; 

rende il codice orribile.

Quindi ... Qual è il modo migliore (e più semplice!) Per garantire la sicurezza del thread?

+0

Penso che sarebbe ancora più chiaro se potessi specificare quale problema stai cercando di risolvere. Non c'è alcun pericolo intrinseco in due thread che impostano un valore globale intorno allo stesso tempo. Il CLR non si arresta in modo anomalo. Che tipo di problema di sincronizzazione stai cercando di risolvere? – PeterAllenWebb

+0

Bene, cosa succede quando un thread sta scrivendo su una stringa mentre un altro sta tentando di leggerlo? Riceverò sempre l'una o l'altra stringa, o potrebbe accadere che io ottenga una stringa parzialmente sovrascritta? – Led

risposta

4

È possibile racchiudere il campo in questione (myConfigString in questo caso) in una proprietà e disporre del codice in Get/Set che utilizza un Monitor.Lock o un Mutex. Quindi, l'accesso alla proprietà blocca solo quel campo singolo e non blocca l'intera classe.

Edit: codice aggiungendo

private static object obj = new object(); // only used for locking 
public static string MyConfigString { 
    get { 
     lock(obj) 
     { 
      return myConfigstring; 
     } 
    } 
    set { 
     lock(obj) 
     { 
      myConfigstring = value; 
     } 
    } 
} 
+0

+1 Inoltre, non è necessario bloccare ints o qualsiasi oggetto che garantisce operazioni atomiche (cioè sicurezza del filo). –

+0

bella cattura! grazie Ed. – Mike

+0

Ed questa è una dichiarazione pericolosa. http://thith.blogspot.com/2005/11/c-interlocked.html – dss539

0

Le configurazioni possono essere 'globale', ma dovrebbero non essere esposto come una variabile globale. Se le configurazioni non cambiano, dovrebbero essere utilizzate per costruire gli oggetti che necessitano delle informazioni - manualmente o attraverso un oggetto factory. Se è possibile modificare, deve essere utilizzato un oggetto che controlla il file di configurazione/database/qualsiasi e implementa lo Observer pattern.

variabili globali (anche quelli che capita di essere un'istanza di classe) sono una brutta cosa ™

+0

in questo caso si tratta principalmente di una stringa che specifica una directory di download che può essere modificata dall'utente in qualsiasi momento. Penso che il pattern Observer potrebbe essere eccessivo per solo 1 o 2 stringhe globali? – Led

+0

Per elaborare, questo non è codice di produzione. Conosco l'etica della programmazione;) Questo è solo un piccolo strumento di progetto per hobby a uso personale. – Led

3

Quanto segue è stato scritto prima di modifica del PO:

public static class Options 
{ 
    private static int _myConfigInt; 
    private static string _myConfigString; 

    private static bool _initialized = false; 
    private static object _locker = new object(); 

    private static void InitializeIfNeeded() 
    { 
     if (!_initialized) { 
      lock (_locker) { 
       if (!_initialized) { 
        ReadConfiguration(); 
        _initalized = true; 
       } 
      } 
     } 
    } 

    private static void ReadConfiguration() { // ... } 

    public static int MyConfigInt { 
     get { 
      InitializeIfNeeded(); 
      return _myConfigInt; 
     } 
    } 

    public static string MyConfigString { 
     get { 
      InitializeIfNeeded(); 
      return _myConfigstring; 
     } 
    } 
    //..etc. 
} 

Dopo che modifica , Posso dire che dovresti fare qualcosa di simile a quanto sopra, e solo impostare la configurazione in un unico posto: la classe di configurazione. In questo modo, sarà l'unica classe a modificare la configurazione in fase di esecuzione e solo quando verrà recuperata un'opzione di configurazione.

+0

Non penso che stia cercando di sincronizzare l'accesso al suo file di configurazione, che è quello che sembra che tu abbia dato. Inoltre, hai fornito l'accesso di sola lettura. – dss539

+0

Ho deliberatamente reso l'accesso di sola lettura. È una classe di configurazione. L'unica cosa che modifica la configurazione dovrebbe essere la classe. –

+0

Errore mio, mi dispiace John, dopo aver riletto la mia domanda ho trovato che fosse troppo vago, quindi ho cercato di elaborare un po '.. – Led

0

Cosa intendi per sicurezza del filo qui? Non è l'oggetto globale che deve essere thread-safe, è il codice di accesso. Se due thread scrivono su una variabile membro vicino allo stesso istante, uno di loro "vincerà", ma è un problema?Se il codice del client dipende dal valore globale che rimane costante fino a quando non viene eseguito con un'unità di elaborazione, sarà necessario creare un oggetto di sincronizzazione per ogni proprietà che deve essere bloccata. Non c'è modo di aggirare questo. È possibile memorizzare nella cache una copia locale del valore per evitare problemi, ma l'applicabilità di tale correzione dipenderà dalle circostanze. Inoltre, non vorrei creare un oggetto di sincronizzazione per ogni proprietà per impostazione predefinita, ma invece ti rendi conto che ne avrai bisogno.

Problemi correlati