Je jouais avec Je m'attendais à ce que le résultat soit "12345", mais c'était "1235 ". En quelque sorte '4' a été mangé. P> si je divisait la ligne x en: p> alors les résultats attendus "12345". P> < p> Pourquoi est-ce tellement? (En utilisant vs2012) p> p> async / attendre code> lorsque je suis tombé sur ce qui suit:
3 Réponses :
Pourquoi est-ce tellement? (En utilisant vs2012) p> blockQuote>
Vous l'exécutez dans une application de console, ce qui signifie qu'il n'y a pas de contexte de synchronisation actuel. P>
En tant que telle, la partie de la méthode
FOOASYNC () code> après que le
attend code> est exécuté dans un fil séparé. Lorsque vous faites
str + = t.result code> Vous faites une condition de course entre le
+ = 4 code> appel et le
+ = t.result code>. C'est parce que
string + = code> n'est pas une opération atomique. P>
Si vous deviez exécuter le même code dans une application Windows Forms ou WPF, le contexte de synchronisation serait capturé et utilisé pour le
+ = "4" code>, ce qui signifie que cela fonctionnerait tous sur le même fil, et vous ne verriez pas ce problème. P>
Comment peut-il y avoir une condition de course si renvoie 5 code> se passe après b>
str + = 4 code> dans le code de
FOOASYNC code>?
@Ilakogan parce que + = code> n'est pas une opération atomique. Il est divisé en plusieurs sous-opérations qui peuvent (et dans ce cas sont) être entrelacées pour générer des résultats indéfinis.
@Ilakogan La condition de course se produit car str + = t.result code> est effectivement
str = str + t.result code> et "str" est extrait avant
+ = 4 code> finitions.
C # déclarations du formulaire Lorsque vous le cassez en deux déclarations, x + = y; code> sont étendus à
x = x + y; code> au moment de la compilation. P>
str + = t.result; code> devient
str = str + t.result; code>, où
str code> est lu avant < / em> obtenir
t.result code>. À ce stade,
str code> est
"123" code>. Lorsque la suite dans
FOOASYNC code> est exécutée, elle modifie
str code>, puis renvoie
5 code>. Donc
str code> est maintenant
"1234" code>. Mais alors la valeur de
str code> qui a été lu avant em> la suite dans
FOOASYNC code> RAN (qui est
"123" code>) est concaténé avec
5 code> pour attribuer à
str code> la valeur
"1235" code>. p>
int i = t.result; str + = i; code>, ce comportement ne peut pas arriver. P>
Le comportement peut encore se produire lorsqu'il est divisé en deux déclarations. C'est juste moins probable. Voir la réponse de Reed.
C'est une condition de race. Vous ne synchronisez pas correctement l'accès à la variable partagée entre les deux threads d'exécution que vous avez.
Votre code fait probablement quelque chose comme ceci: p>
Ensuite, nous arrivons à la ligne intéressante: p> Ici, il est divisé en plusieurs opérations plus petites. Il va d'abord obtenir la valeur actuelle de Le rappel ASYNC aura attrapé et re-définir str code>. À ce stade, la méthode ASYNC (dans toutes les probabilités) n'a pas encore fini, ce sera donc
"123" code>. Il attend ensuite que la tâche achète (car
résultat code> force une attente de blocage) et ajoute le résultat de la tâche, dans ce cas
5 code> à la fin de la chaîne. < / p>
str code> après em> le fil principal avait déjà saisi la valeur actuelle de
STR code> , puis il écrasera
str code> sans qu'il soit lu comme le fil principal est bientôt pour écraser. p> p>
Le pourquoi est certainement intéressant, mais il convient également de noter que vous ne devez pas faire cela - l'accès partagé à une variable avec des opérations qui ne sont pas atomiques sans serrures ni autre logique de threading ne sont sûrs que de vous mettre dans des situations indéterminées.