72 votes

Interloqué et volatile

J'ai une variable que j'utilise pour représenter l'état. Il peut être lu et écrit à partir de plusieurs threads.

Je suis l'aide d' Interlocked.Exchange et Interlocked.CompareExchange de la changer. Cependant, je vais le lire à partir de plusieurs threads.

Je sais qu' volatile peut être utilisé pour s'assurer que la variable n'est pas mis en cache localement, mais qui se lit toujours directement à partir de la mémoire.

Cependant si j'ai mis la variable volatile ensuite, il génère un message d'avertissement sur l'utilisation de volatiles et de passage à l'aide de ref pour le Contrefil méthodes.

Je veux m'assurer que chaque thread est la lecture la plus récente de la valeur de la variable et non une version mise en cache, mais je ne peux pas utiliser volatile.

Il y a un Interlocked.Read mais c'est pour la version 64 bits types et n'est pas disponible sur le compact framework. La documentation car il dit qu'il n'est pas nécessaire pour la version 32 bits types car ils sont déjà effectué en une seule opération.

Il y a des déclarations faites à travers l'internet qui vous n'avez pas besoin volatile si vous utilisez le Contrefil méthodes pour tous vos accès. Cependant, vous ne pouvez pas lire un 32 bits variable à l'aide de la Contrefil méthodes, donc il n'y a aucun moyen que vous pouvez utiliser Contrefil méthodes pour tous vos accès.

Est-il un moyen pour accomplir le "thread-safe" lire et écrire de ma variable sans l'aide de serrure?

42voto

Anton Tykhyy Points 12680

Vous pouvez en toute sécurité ignorer cet avertissement lorsque vous utilisez Interlocked.Xxx fonctions (voir cette question), car ils le font toujours volatile des opérations. Ainsi, un volatile variable est parfaitement OK pour le partage de l'état. Si vous voulez vous débarrasser de l'avertissement à tous les frais, vous pouvez faire un contrefil lire avec Interlocked.CompareExchange (ref counter, 0, 0).

Edit: en Fait, vous avez besoin d' volatile sur votre variable d'état uniquement si vous vous apprêtez à écrire directement (c'est à dire n'utilisant pas d' Interlocked.Xxx). Comme jerryjvl mentionné, se lit d'une variable de mises à jour avec un contrefil (ou volatilité) opération va utiliser la valeur la plus récente.

42voto

jerryjvl Points 9310

Interloqué des opérations et de la volatilité n'êtes pas vraiment censé être utilisés en même temps. La raison pour laquelle vous obtenez un message d'avertissement est parce qu'elle a (presque?) toujours vous indique que vous avez mal compris ce que vous faites.

La sur-simplification et de la paraphrase:
volatile indique que chaque opération de lecture doit re-lecture de la mémoire parce qu'il pourrait y avoir d'autres threads mise à jour de la variable. Lorsqu'il est appliqué à un champ qui peut être lu/écrit atomiquement par l'architecture vous sont en cours d'exécution, ce devrait être tout ce que vous devez faire, sauf si vous utilisez long/ulong, la plupart des autres types de données peuvent être lues/écrites de manière atomique.

Lorsqu'un champ n'est pas marqué volatile, vous pouvez utiliser Interlocked des opérations à faire une semblable garantie, car elle provoque la purge du cache, de sorte que la mise à jour sera visible pour tous les autres processeurs... cela a pour avantage de vous mettre la surcharge sur la mise à jour plutôt que de le lire.

Laquelle de ces deux approches donnent de meilleurs résultats dépend exactement ce que vous êtes en train de faire. Et cette explication est une grossière simplification. Mais il devrait être clair à partir de ce que font les deux en même temps est inutile.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X