2009-05-28 8 views
6

Dans une application C#, supposons que j'ai une seule classe mondiale qui contient des éléments de configuration, comme suit:C# fil de sécurité des paramètres de configuration globale

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

static Options GlobalOptions; 

les membres de cette classe seront utilisations à travers différents threads:

Thread1: GlobalOptions.myConfigString = blah; 

tout

Thread2: string thingie = GlobalOptions.myConfigString; 

Utilisation d'un cadenas pour l'accès aux GlobalOptions L'objet serait également inutile lorsque 2 threads accèdent à des membres différents, mais d'un autre côté, créer un objet de synchronisation pour chaque membre semble également un peu trop haut. De plus, utiliser un verrou sur les options globales rendrait mon code moins sympa je pense; si je dois écrire

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

partout (et est-ce thread-safe ou est stringiwanttouse maintenant juste un pointeur vers myConfigString? Oui, je suis nouveau à C# ....) au lieu de

string stringiwanttouse = GlobalOptions.myConfigString; 

cela rend le code horrible.

Alors ... Quelle est la meilleure (et la plus simple!) Façon d'assurer la sécurité des filetages?

+0

Je pense que ce serait encore plus clair si vous pouviez spécifier quel problème vous essayez de résoudre. Il n'y a pas de danger inhérent à deux threads définissant une valeur globale à peu près au même moment. Le CLR ne va pas tomber en panne. Quel genre de problème de synchronisation essayez-vous de résoudre? – PeterAllenWebb

+0

Eh bien, que se passe-t-il lorsqu'un thread écrit dans une chaîne alors qu'un autre essaie de le lire? Est-ce que j'obtiendrai toujours l'une ou l'autre chaîne, ou est-ce que je pourrais avoir une chaîne partiellement écrasée? – Led

Répondre

4

Vous pouvez recouvrir le champ en question (myConfigString dans ce cas) dans une propriété et avoir du code dans le Get/Set qui utilise un Monitor.Lock ou un Mutex. Ensuite, l'accès à la propriété verrouille uniquement ce champ unique et ne verrouille pas la classe entière.

Edit: ajout de code

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 De plus, vous n'avez pas besoin de verrouiller les entrées ou tout objet qui garantit les opérations atomiques (c'est-à-dire la sécurité des threads). –

+0

belle prise! thx Ed. – Mike

+0

Ed c'est une déclaration dangereuse. http://thith.blogspot.com/2005/11/c-interlocked.html – dss539

0

Vos configurations peuvent être 'globale', mais ils ne devraient pas être exposé comme une variable globale. Si les configurations ne changent pas, elles doivent être utilisées pour construire les objets qui ont besoin des informations - manuellement ou via un objet d'usine. Si elles peuvent changer, alors un objet qui regarde le fichier de configuration/base de données/tout et implémente le Observer pattern doit être utilisé.

Les variables globales (même ceux qui se trouvent être une instance de classe) sont une mauvaise chose ™

+0

Dans ce cas, il s'agit principalement d'une chaîne spécifiant un répertoire de téléchargement qui peut être modifié par l'utilisateur à tout moment. Je pense que le modèle Observer peut être surdimensionné pour seulement 1 ou 2 chaînes globales? – Led

+0

Pour élaborer, ce n'est pas le code de production. Je connais l'éthique de la programmation;) Ceci est juste un petit outil de projet de passe-temps pour mon propre usage. – Led

3

Ce qui suit a été écrit avant l'édition de l'OP:

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. 
} 

Après cette édition , Je peux dire que vous devriez faire quelque chose comme ci-dessus, et seulement configurer la configuration dans un seul endroit - la classe de configuration. De cette façon, il sera la seule classe à modifier la configuration au moment de l'exécution, et seulement lorsqu'une option de configuration doit être récupérée.

+0

Je ne pense pas qu'il essaie de synchroniser l'accès à son fichier de configuration, ce qui ressemble à ce que vous avez donné. En outre, vous avez fourni un accès en lecture seule. – dss539

+0

J'ai délibérément fait l'accès en lecture seule. C'est une classe de configuration. La seule chose qui modifie la configuration devrait être la classe. –

+0

Mon erreur, désolé John, après avoir relu ma question je l'ai trouvé trop vague en effet donc j'ai essayé d'élaborer un peu .. – Led

0

Qu'entendez-vous par sécurité des filetages ici? Ce n'est pas l'objet global qui doit être thread safe, c'est le code d'accès. Si deux threads écrivent dans une variable membre près du même instant, l'un d'entre eux va "gagner", mais est-ce un problème?Si votre code client dépend de la valeur globale restant constante jusqu'à ce que cela soit fait avec une unité de traitement, vous devrez créer un objet de synchronisation pour chaque propriété qui doit être verrouillée. Il n'y a pas de bon moyen de contourner cela. Vous pouvez simplement mettre en cache une copie locale de la valeur pour éviter les problèmes, mais l'applicabilité de cette correction dépend de votre situation. De plus, je ne créerais pas d'objet de synchronisation pour chaque propriété par défaut, mais plutôt que vous réaliserez que vous en aurez besoin.

Questions connexes