6
votes

C # Filetage: Exemple de condition de course

Je lis je lis http://www.mono-project.com/threadsbeginnersguide . < p> Le premier exemple ressemble à ceci: xxx

sortie: xxx

wow, qu'est-ce que c'est? Malheureusement, l'explication de l'article est inadéquate pour moi. Pouvez-vous m'expliquer pourquoi les incréments sont arrivés dans un ordre jumblé?

merci!


1 commentaires

L'auteur de l'article mentionné indique la sortie "peut" être comme indiqué. Cela est vrai dans le sens où vous ne pouvez pas prouver que la sortie ne serait pas comme indiqué. Toutefois, dans la pratique, étant donné que cela est donné d'abord environ 10 MS Head Start, vous vous attendriez à voir une alternance de l'étape de verrouillage pour des itérations assez nombreuses avant tout «mêlée».


4 Réponses :


2
votes

La synchronisation est essentielle lorsque plusieurs threads sont présents. Dans ce cas, vous voyez que les deux threads lisent et écrivent à this.i , mais aucune bonne tentative n'est effectuée pour synchroniser ces accès. Étant donné que les deux modifient simultanément la même zone de mémoire, vous observez la sortie jumblée. L'appel au sommeil est dangereux, c'est une approche qui mène à des bugs sûrs. Vous ne pouvez pas supposer que les threads seront toujours déplacés par l'inital de 10 ms.

En bref: N'utilisez jamais de sommeil pour la synchronisation :-) Mais adoptez plutôt une sorte de technique de synchronisation de fil (serrures, mutiles, sémaphores). Essayez toujours d'utiliser la serrure la plus légère possible qui remplira votre besoin ...

Une ressource utile est le livre de Joe Duffy, programmation simultanée sous Windows.


3 commentaires

Je ne pense pas que thread.sleep () est utilisé pour essayer de synchroniser les threads. Il est juste utilisé pour que les incréments soient observables (sinon, il apparaisse tout simplement à la fois sur la console), qui a un effet secondaire de réduire les risques d'une condition de race presque nulle.


Oui, le commentaire dit que, mais il est utilisé comme une technique de synchronisation approximative, examinez le gaste de 10 ms entre les deux appels à démarrer (). En l'absence d'autres techniques, il me semble que le sommeil fait semblant une synchronisation entre les deux threads.


+1 pour le livre Joe Duffy, c'est la Bible de la concurrence Windows



0
votes

Les incréments ne se produisent pas hors de l'ordre, la console.writeline (...) écrit la sortie de plusieurs threads dans une console unique à une console à une seule filetage, et la synchronisation à partir de nombreux threads à un thread est à l'origine des messages. hors de commande.

Je suppose que cet exemple a tenté de créer une condition de course, et dans votre cas échoué. Malheureusement, des problèmes de concurrence, tels qu'une condition de race et des blocages, sont difficiles à prédire et à se reproduire en raison de leur nature. Vous voudrez peut-être essayer de l'exécuter quelques fois de plus, modifiez-le d'utiliser plus de threads et chaque thread devrait augmenter plus de fois (disons 100 000). Ensuite, vous pourriez voir que le résultat final ne sera pas égal à la somme de tous les incréments (causés par une condition de race).


1 commentaires

Désolé, console.writeine. Corrigée.



2
votes

Quand j'exécute cela (sur un Dualcore), ma sortie est xxx

comme je l'aurais attendu. Vous courez deux boucles, les deux exécutant le sommeil (100). C'est très mal adapté pour démontrer une crique.

Le code a une condition de course (comme indique le votedisclette) mais il est très peu probable de surface.

Je ne peux pas expliquer le manque d'ordre dans votre sortie (est-ce un Vitesse réelle?), mais la classe de la console synchronisera les appels de sortie.

Si vous laissez les appels de veille () et exécutez les boucles 1000 fois (au lieu de 10), vous pouvez voir deux coureurs à la fois progressivement de 554 à 555 ou quelque chose.


2 commentaires

Je viens de copier ce que l'article avait, cependant, je pouvais obtenir une sortie simulée similaire en supprimant le sommeil initial dans le programme et en abaissant les couchages dans les fils à 20.


Vous avez raison, la cause est de la synchronisation de la console.



3
votes

Je pense que l'écrivain de l'article a confondu des choses confuses.

voteydisciple est correct que ++ i n'est pas atomique et une condition de course peut se produire si la cible n'est pas verrouillée pendant l'opération mais Cela ne provoquera pas le problème décrit ci-dessus.

Si une condition de raccourci a lieu appelant ++ i alors les opérations internes du ++ comme: -

  1. 1er thread lit la valeur 0
  2. 2e fil lit la valeur 0
  3. 1er thread incrémente la valeur à 1
  4. 2e thread incrémente la valeur à 1
  5. 1er thread écrit la valeur 1
  6. 2e fil écrit la valeur 1

    L'ordre des opérations 3 à 6 est sans importance, le point est que les opérations de lecture, 1 et 2 peuvent survenir lorsque la variable a une valeur x résultant de la même incrémentation de y, plutôt que chaque thread Effectuer des incrémentations pour des valeurs distinctes de x et y.

    Ceci peut entraîner la sortie suivante: - xxx

    Quel serait encore pire est ce qui suit: -

    1. 1er thread lit la valeur 0
    2. 2e fil lit la valeur 0
    3. 2e thread incrémente la valeur à 1
    4. 2e fil écrit la valeur 1
    5. 2nd thread lit la valeur 1
    6. 2e fileté incréments de valeur à 2
    7. 2nd thread écrit la valeur 2
    8. 1er thread incrémente la valeur à 1
    9. 1er thread écrit la valeur 1
    10. 2nd thread lit la valeur 1
    11. 2e fileté incréments de valeur à 2
    12. 2nd thread écrit la valeur 2

      Cela peut entraîner la sortie suivante: - xxx

      et ainsi de suite.

      En outre, il y a une condition de race possible entre la lecture i et effectuer ++ i car la console.writeline appelle concaténatets i et ++ i . Cela peut entraîner une sortie comme: - xxx

      la sortie de la console jumblée que l'auteur a décrit ne peut résulter que de l'imprévisibilité de la sortie de la console et n'a rien à voir avec une course Condition sur la variable i . Prendre un verrouillage sur i tandis que vous effectuez ++ i ou tout en concaténant i et ++ i ne changera pas cela comportement.


0 commentaires