117 votes

L'affectation de référence est atomique, alors pourquoi Interlocked.Exchange (Ref Object, Object) est-il nécessaire?

Dans mon multithread service web asmx j'avais un champ de classe _allData de mon propre type SystemData qui se compose de quelques List<T> et Dictionary<T> marqués volatile. Le système de données (_allData) est actualisée une fois dans un certain temps et je le fais par la création d'un autre objet appelé newData et le remplir de structures de données avec de nouvelles données. Quand c'est fait, je viens de céder

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 depuis la cession est atomique et les fils qui ont la référence à des données anciennes continuer à l'utiliser et le reste du nouveau système de données juste après la cession. Cependant, mon collegue a dit qu'au lieu d'utiliser volatile mot-clé et simple affectation que je devrais utiliser InterLocked.Exchange car il a dit que, sur certaines plateformes, il n'est pas garanti que la référence affectation est atomique. Par ailleurs: quand je déclare the _allData champ volatile le

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

produit d'avertissement "une référence à un champ volatile ne seront pas traités comme volatile" Que dois-je penser de cela?

195voto

Eric Lippert Points 300275

Les questions sont nombreuses ici. En les examinant une à une:

référence affectation est atomique alors pourquoi est Interloqué.De change(réf Object, Object) nécessaires?

Référence affectation est atomique. Interloqué.L'échange ne fait pas seulement référence de la mission. Il fait une lecture de la valeur actuelle d'une variable, caches loin l'ancienne valeur, et affecte la nouvelle valeur à la variable, tout comme une opération atomique.

mon collègue a dit que, sur certaines plateformes, il n'est pas garanti que la référence affectation est atomique. A mon collègue correct?

Pas de. Référence affectation est garanti d'être atomique sur tous .NET plates-formes.

Mon collègue est le raisonnement à partir de prémisses fausses. Est-ce à dire que leurs conclusions sont erronées?

Pas nécessairement. Votre collègue pourrait vous donner de bons conseils pour les mauvaises raisons. Peut-être il ya une autre raison pourquoi vous devriez être à l'aide de Contrefil.Exchange. Sans verrouillage de la programmation est incroyablement difficile, et le moment où vous partez de pratiques bien établies, épousée par des experts dans le domaine, vous êtes hors de la mauvaises herbes et de risquer le pire genre de 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 manière ou l'autre.

produit d'avertissement "une référence à un champ volatile ne seront pas traités comme volatile" Que dois-je penser de cela?

Vous devez comprendre pourquoi c'est un problème général. Qui mènera à une compréhension des raisons pour lesquelles l'avertissement est sans importance dans ce cas particulier.

La raison que le compilateur donne cet avertissement, c'est parce que le marquage d'un champ, alors que la volatilité signifie "ce champ va être mise à jour sur plusieurs threads-ne pas générer un code qui met en cache les valeurs de ce champ, et assurez-vous que toute lecture ou de l'écriture de ce champ ne sont pas "déplacé en avant et en arrière dans le temps" par l'intermédiaire de cache du processeur incohérences."

(Je suppose que vous comprenez déjà tout ça. Si vous n'avez pas une compréhension détaillée de la signification de la volatilité et de son impact sur le cache du processeur sémantique, alors vous ne pouvez pas comprendre comment il fonctionne et ne doit pas être à l'aide de volatiles. Sans verrouillage des programmes sont très difficiles à obtenir; assurez-vous que votre programme est bon, parce que vous comprenez comment cela fonctionne, pas de droit par accident.)

Maintenant, supposons que vous faites une variable qui est un alias de champ volatile par le passage d'une référence à ce champ. À l'intérieur de la méthode appelée, le compilateur n'a pas de raison que ce soit, à savoir que la référence doit avoir de la volatilité de la sémantique! Le compilateur va gaiement générer du code pour la méthode qui ne parvient pas à mettre en œuvre les règles de la volatilité des champs, mais la variable est un champ volatile. Qui peut complètement détruire vos sans verrouillage de la logique; l'hypothèse est toujours celle d'un champ volatile est toujours accessible à la volatilité de la sémantique. Il ne fait aucun sens de la traiter comme volatile parfois, et pas à d'autres moments; vous devez toujours être cohérent sinon vous ne pouvez pas garantir la cohérence sur les autres accès.

Par conséquent, le compilateur avertit lorsque vous faites cela, parce que c'est probablement va complètement ruiner votre soigneusement élaboré sans verrouillage de la logique.

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

9voto

Guffa Points 308133

Votre collègue se trompe, ou qu'il sait quelque chose que la spécification du langage C# ne fonctionne pas.

5.5 l'Atomicité des références à des variables:

"Les lectures et les écritures suivantes types de données sont atomiques: bool, char, octet, sbyte, short, ushort, uint, int, float, et les types référence."

Donc, vous pouvez écrire à la volatilité de référence sans risque de contracter une valeur endommagée.

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

7voto

Guillaume Points 5649

Interloqué.Exchange< T >

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

Elle change et renvoie la valeur d'origine, c'est inutile parce que vous ne voulez le changer et, comme Guffa dit, c'est déjà atomique.

À moins d'un profiler comme prouvé à être un goulot d'étranglement dans votre application, vous devriez envisager de unsing de serrures, il est plus facile de comprendre et de prouver que votre code est bon.

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