affectation de référence est atomique, alors pourquoi est Interlocked.Exchange (ref Object, Object) nécessaire?

StackOverflow https://stackoverflow.com/questions/2192124

Question

Dans mon service Web multithread asmx J'ai eu un champ de classe _allData de mon propre type SystemData qui se compose de quelques List<T> et Dictionary<T> marqués comme volatile. Les données du système (_allData) est rafraîchi de temps en temps et je le fais en créant un autre objet appelé newData et remplir c'est des structures de données avec de nouvelles données. Une fois terminé, j'Assignez simplement

private static volatile SystemData _allData

public static bool LoadAllSystemData()
{
    SystemData newData = new SystemData();
    /* fill newData with up-to-date data*/
     ...
    _allData = newData.
} 

Cela devrait fonctionner puisque l'affectation est atomique et les fils qui ont la référence aux anciennes données continuer à l'utiliser et le reste que les nouvelles données du système juste après l'affectation. Cependant, mon collègue a dit qu'au lieu d'utiliser de mot-clé volatile et assigment simple que je devrais utiliser InterLocked.Exchange parce qu'il a dit que sur certaines plates-formes, il n'est pas garanti que l'affectation de référence est atomique. De plus: quand je déclare champ the _allData comme volatile le

Interlocked.Exchange<SystemData>(ref _allData, newData); 

avertissement produit des « une référence à un champ volatile ne sera pas considéré comme volatil » Que dois-je penser à ce sujet?

Était-ce utile?

La solution

Il y a de nombreuses questions. Considérant les un à la fois:

  

affectation de référence est atomique, alors pourquoi est Interlocked.Exchange (ref Object, Object) nécessaire?

Affectation de référence est atomique. Interlocked.Exchange ne fait pas seulement l'affectation de référence. Il fait une lecture de la valeur actuelle d'une variable, la valeur cache profondément ancienne, et attribue la nouvelle valeur à la variable, tout comme une opération atomique.

  

mon collègue a dit que sur certaines plates-formes, il n'est pas garanti que l'affectation de référence est atomique. Est-ce que mon collègue corriger?

Non. Affectation de référence est garantie atomique sur toutes les plateformes .NET.

  

Mon collègue raisonne de fausses prémisses. Est-ce que cela signifie que leurs conclusions sont incorrectes?

Pas nécessairement. Votre collègue pourrait être vous donner de bons conseils pour de mauvaises raisons. Peut-être il y a une autre raison pour laquelle vous devez utiliser Interlocked.Exchange. programmation lock-gratuit est incroyablement difficile et le moment où vous partiez de pratiques bien établies par des experts embrassées dans le domaine, vous êtes hors dans les mauvaises herbes et de risquer le pire des conditions de course. Je ne suis ni un expert dans ce domaine, ni un expert sur votre code, donc je ne peux pas faire un jugement d'une façon ou l'autre.

  

avertissement produit des « une référence à un champ volatile ne sera pas considéré comme volatil » Que dois-je penser à ce sujet?

Vous devez comprendre pourquoi cela est un problème en général. Cela conduira à une meilleure compréhension des raisons pour lesquelles l'avertissement est sans importance dans ce cas particulier.

La raison pour laquelle le compilateur donne cet avertissement est parce que marquer un champ comme moyen volatile « ce champ va être mis à jour sur plusieurs threads - ne génère pas de code qui met en cache les valeurs de ce champ, et assurez-vous que tout lit ou écritures de ce champ ne sont pas « déplacé vers l'avant et vers l'arrière dans le temps » par les incohérences du cache du processeur « .

(je suppose que vous comprenez déjà tout cela. Si vous ne disposez pas d'une compréhension détaillée de la signification des volatiles et son impact sur la sémantique du cache du processeur alors vous ne comprenez pas comment il fonctionne et ne devrait pas utiliser volatile. Verrouillage programmes -free sont très difficiles à obtenir le droit, assurez-vous que votre programme est juste parce que vous comprenez comment cela fonctionne, pas juste par accident)

.

Maintenant, supposons que vous faites une variable qui est un alias d'un champ volatile en passant une ref à ce domaine. Dans la méthode appelée, le compilateur n'a aucune raison de savoir que la référence doit avoir une sémantique volatile! Le compilateur génère allègrement code pour la méthode qui ne parvient pas à mettre en œuvre les règles pour les champs volatils, mais la variable est un champ volatile. Cela peut complètement ruiner votre logique sans serrure; l'hypothèse est toujours un champ volatile est toujours avec accès sémantique volatile. Il ne fait aucun sens de le traiter comme parfois volatils et non d'autres fois; vous devez toujours être cohérent, sinon vous ne pouvez pas garantir la cohérence d'autres accès.

Par conséquent, le compilateur avertit lorsque vous faites cela, parce qu'il va probablement complètement gâcher votre logique sans verrou soigneusement mis au point.

Bien sûr, Interlocked.Exchange est par écrit à attendre un champ volatile et faire la bonne chose. L'avertissement est donc trompeur. Je regrette beaucoup; ce que nous aurions dû faire est de mettre en œuvre un mécanisme par lequel un auteur d'une méthode comme Interlocked.Exchange pourrait mettre un attribut sur la méthode disant: « cette méthode qui prend une ref applique la sémantique volatile sur la variable, donc supprimer l'avertissement ». Peut-être dans une future version du compilateur, nous le ferons.

Autres conseils

Soit votre collegue se trompe, ou il sait quelque chose que la spécification du langage C # ne fonctionne pas.

5.5 atomicité de références variables :

  

"Lecture et écriture de ce qui suit   les types de données sont atomiques: bool, char,   octet, sbyte, court, ushort, uint, int,   flotter, et les types de référence. "

Alors, vous pouvez écrire à la référence volatile sans risque d'obtenir une valeur corrompue.

Vous devez bien sûr être prudent avec la façon dont vous décidez quel thread devrait chercher les nouvelles données, afin de minimiser le risque que plus d'un thread à la fois le fait.

Interlocked.Exchange

  

définit une variable du T de type spécifié à une valeur spécifiée et retourne la valeur d'origine, comme une opération atomique.

Il change et retourne la valeur d'origine, il est inutile parce que vous voulez seulement changer et, comme l'a dit Guffa, il est déjà atomique.

A moins d'un profileur comme prouvé être un goulot d'étranglement dans votre application, vous devriez considérer les serrures unsing, il est plus facile à comprendre et à prouver que votre code est bon.

Iterlocked.Exchange() est non seulement atomique, il prend également en charge de la visibilité de la mémoire:

  

Les fonctions de synchronisation suivants utilisent les barrières appropriées pour assurer la commande de la mémoire:

     

Les fonctions qui entrent ou sortent des sections critiques

     

Fonctions qui signalent des objets de synchronisation

     

fonctions d'attente

     

Fonctions verrouillables

synchronisation et multiprocesseurs Problèmes

Cela signifie qu'en plus de atomicité il assure que:

  • Pour le fil appelant:
    • Non réordonnancement des instructions est fait (par le compilateur, l'exécution ou le matériel).
  • Pour toutes les discussions:
    • Pas de lit à la mémoire qui se passe avant cette instruction verra le changement cette instruction fait.
    • Tous lit après cette instruction verra la modification apportée par cette instruction.
    • Tous écrit à la mémoire après cette instruction va se passer après ce changement d'instruction a atteint la mémoire principale (en rinçant ce changement d'instruction à la mémoire principale lorsque son fait et ne pas laisser le matériel débusquer son propre son sur le calendrier).
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top