2009-09-04 4 views
2

Est-ce que quelqu'un peut expliquer pourquoi les exemples sur le thread vont toujours rendre un objet statique (spécifiquement une variable membre) statique s'il doit être accédé par plusieurs threads?C#: Question concernant la sécurité des threads pour les variables membres

Mon problème est que rendre statique la variable membre signifie qu'elle sera partagée entre toutes les autres instanciations de la classe. Parfois, je trouve que j'aimerais que plusieurs threads au sein d'une classe "touchent" la variable membre mais permettent en même temps à chaque objet d'avoir sa propre copie.

La réponse à exécuter ce que je disais simplement remplacerai:

  • utilisant le mot clé volatile
  • Utilisation du verrouillage (objet)

Répondre

3

Si vous voulez que chaque thread utilise la même variable membre, mais conserve également une copie séparée, vous avez une contradiction ici. Soit ils utilisent la même variable ou ils ne le font pas. Sauf si je ne te comprends pas bien. Cela dit, si vous avez réellement besoin d'un champ statique accessible par plusieurs threads, chacun conservant sa propre valeur privée, vous pouvez utiliser l'attribut ThreadStatic. Cet attribut garantit que le champ statique sera privé pour chaque thread ("thread local" comme il est habituellement appelé).

[ThreadStatic] 
private static bool s_threadHasDoneItsWork; 

Notez que vous ne pouvez pas initialiser un champ statique local fil par un constructeur statique ou directement static type field = value. (Le compilateur ne se plaindra pas, mais il ne fonctionnera pas correctement.)


volatile indique le temps d'exécution que le champ (statique ou non) doit toujours être accessible directement depuis la mémoire principale, de sorte que vous n » t besoin d'utiliser des verrous ou des barrières de mémoire pour synchroniser les threads et les cœurs. Il est toujours à jour, pour ainsi dire, alors que d'autres champs peuvent toujours attendre que le cache mémoire de votre processeur se synchronise avec votre mémoire principale.

Mais c'est exactement la limite de ce qu'il fait: seulement accès à ce domaine particulier. Dès que vous l'avez lu, la valeur est de nouveau obsolète, donc ne pensez jamais à faire quelque chose comme volatileField ++ (ce qui signifie "lire volatileField, ajouter un à la valeur que vous venez de lire, définir volatileField", et non "increment volatileField", vous devrez utiliser la classe Interlocked pour cela, ce qui est beaucoup plus cher).

Un moyen sûr d'utiliser les champs volatiles est de les lire directement, mais lorsque vous les modifiez, utilisez un mécanisme de verrouillage avant de les lire ou de les écrire. (La seule exception raisonnable à laquelle je puisse penser est un drapeau booléen comme "J'ai fini maintenant".

L'utilisation pratique de champs volatils est, de manière non surprenante, plutôt limitée. Stick avec un verrouillage simple; le mot-clé lock et les méthodes correspondantes de la classe Monitor prennent en charge à la fois la synchronisation de la mémoire de l'utilisateur unique et (dès que vous entrez et sortez du verrou).

+0

Oui J'ai vu l'attribut de Threadstatic sur le MSDN et il a confondu l'enfer hors de moi. Il semble aller à l'encontre de la définition d'une variable statique si chaque thread maintient sa propre copie personnelle. – Setheron

+0

C'est en quelque sorte, oui. Mais cela peut être utile si vous devez maintenir un état spécifique au thread, ou indiquer que les méthodes qui sont appelées depuis l'une de vos méthodes doivent pouvoir y accéder, mais personne d'autre. En fonction de son utilisation, le stockage local des threads peut éviter la synchronisation des threads (car il n'y a pas de partage entre les threads), ce qui peut être utile. – Ruben

+0

n'a même pas de sens pourquoi il aurait alors besoin du champ statique. Threadstatic seul devrait alors avoir du sens. – Setheron

8

Il n'y a rien qui exige des variables membres à être statique enfilage

La plupart des exemples utilisent une variable statique, en particulier parce qu'ils essaient de montrer comment synchroniser les données entre deux threads distincts. Si vous souhaitez le faire, vous devez avoir une valeur accessible par les deux threads. Les variables statiques sont l'option la plus simple, puisqu'elles sont accessibles partout.

Vous pouvez tout aussi facilement transmettre une référence à une classe dans votre thread et faire en sorte que ce thread et votre thread principal partagent une variable membre non statique. Cependant, vous devrez fournir un bon mécanisme de verrouillage/synchronisation, car vous aurez deux threads partageant une instance d'une classe.

+0

Le mot clé volatile doit-il être inclus avec static? N'y a-t-il pas des soucis avec la mise en antémémoire de la valeur statique dans un thread et l'absence de la plus récente dans l'autre thread? – Setheron

+0

@Setheron: utilisez toujours 'lock (object)' pour accéder aux variables partagées par plusieurs threads. Cela vous donnera un accès exclusif et fera tout pour vous afin que tous les threads obtiennent toujours les valeurs les plus récentes (barrière de mémoire). – dtb

+0

Voir ma réponse pour l'utilisation de volatile. Dans la plupart des cas pratiques, vous pouvez complètement ignorer qu'il existe. (Bien qu'un gourou volatil puisse probablement faire un cas splendide pour volatil, à mon humble avis, vous n'en aurez pas besoin.) – Ruben

Questions connexes