Lors de l'écriture d'applications multithreads, l'un des problèmes les plus courants rencontrés est les conditions de concurrence.
Mes questions à la communauté sont:
Quelle est la condition de course?
Comment les détectez-vous?
Comment les gérez-vous?
Enfin, comment les empêchez-vous de se produire?
multithreading
concurrency
terminology
race-condition
bmurphy1976
la source
la source
Réponses:
Une condition de concurrence critique se produit lorsque deux threads ou plus peuvent accéder aux données partagées et qu'ils essaient de les modifier en même temps. Étant donné que l'algorithme de planification des threads peut à tout moment basculer entre les threads, vous ne connaissez pas l'ordre dans lequel les threads tenteront d'accéder aux données partagées. Par conséquent, le résultat de la modification des données dépend de l'algorithme de programmation des threads, c'est-à-dire que les deux threads sont "en course" pour accéder / modifier les données.
Des problèmes surviennent souvent lorsqu'un thread effectue un "check-then-act" (par exemple "check" si la valeur est X, puis "agir" pour faire quelque chose qui dépend de la valeur étant X) et un autre thread fait quelque chose à la valeur dans entre le "chèque" et l '"acte". Par exemple:
Le fait est que y pourrait être 10, ou n'importe quoi, selon qu'un autre thread a changé x entre la vérification et l'acte. Vous n'avez aucun moyen réel de savoir.
Afin d'éviter que des conditions de concurrence critique ne se produisent, vous devez généralement verrouiller les données partagées pour vous assurer qu'un seul thread peut accéder aux données à la fois. Cela signifierait quelque chose comme ceci:
la source
Une «condition de concurrence critique» existe lorsqu'un code multithread (ou autrement parallèle) qui accéderait à une ressource partagée pourrait le faire de manière à provoquer des résultats inattendus.
Prenez cet exemple:
Si vous aviez 5 threads exécutant ce code à la fois, la valeur de x NE SERAIT PAS 50 000 000. En fait, cela varierait à chaque passage.
C'est parce que, pour que chaque thread incrémente la valeur de x, ils doivent faire ce qui suit: (simplifié, évidemment)
N'importe quel thread peut être à n'importe quelle étape de ce processus à tout moment et ils peuvent marcher l'un sur l'autre lorsqu'une ressource partagée est impliquée. L'état de x peut être modifié par un autre thread pendant la période entre la lecture de x et sa réécriture.
Disons qu'un thread récupère la valeur de x, mais ne l'a pas encore stockée. Un autre thread peut également récupérer la même valeur de x (car aucun thread ne l'a encore changé) et ils stockeront tous les deux la même valeur (x + 1) dans x!
Exemple:
Les conditions de concurrence peuvent être évitées en utilisant une sorte de mécanisme de verrouillage avant le code qui accède à la ressource partagée:
Ici, la réponse ressort à 50 000 000 à chaque fois.
Pour plus d'informations sur le verrouillage, recherchez: mutex, sémaphore, section critique, ressource partagée.
la source
Vous prévoyez d'aller voir un film à 17 h. Vous vous renseignez sur la disponibilité des billets à 16h. Le représentant dit qu'ils sont disponibles. Vous vous détendez et atteignez le guichet 5 minutes avant le spectacle. Je suis sûr que vous pouvez deviner ce qui se passe: c'est une maison pleine. Le problème ici était dans la durée entre le contrôle et l'action. Vous vous êtes renseigné à 4 heures et avez agi à 5 heures. Entre-temps, quelqu'un d'autre a saisi les billets. C'est une condition de course - spécifiquement un scénario "check-then-act" des conditions de course.
Révision du code religieux, tests unitaires multithread. Il n'y a pas de raccourci. Il y a peu de plugins Eclipse émergeant à ce sujet, mais rien de stable pour le moment.
La meilleure chose serait de créer des fonctions sans effets secondaires et sans état, d'utiliser autant que possible des immuables. Mais ce n'est pas toujours possible. Donc, en utilisant java.util.concurrent.atomic, des structures de données simultanées, une synchronisation appropriée et une concurrence basée sur les acteurs vous aideront.
La meilleure ressource pour la concurrence est JCIP. Vous pouvez également obtenir plus de détails sur l'explication ci-dessus ici .
la source
Il existe une différence technique importante entre les conditions de course et les courses de données. La plupart des réponses semblent supposer que ces termes sont équivalents, mais ils ne le sont pas.
Une course aux données se produit lorsque 2 instructions accèdent au même emplacement de mémoire, au moins un de ces accès est une écriture et il n'y a aucun événement avant de passer une commande parmi ces accès. Maintenant, ce qui constitue un événement avant la commande est sujet à de nombreux débats, mais en général, les paires ulock-lock sur la même variable de verrouillage et les paires de signaux d'attente sur la même variable de condition induisent un ordre passe-avant.
Une condition de concurrence est une erreur sémantique. Il s'agit d'une faille qui se produit dans le calendrier ou l'ordre des événements qui conduit à un comportement erroné du programme .
De nombreuses conditions de course peuvent être (et sont en fait) causées par des courses de données, mais ce n'est pas nécessaire. En fait, les courses de données et les conditions de course ne sont ni nécessaires ni suffisantes les unes pour les autres. Ce billet de blog explique également très bien la différence, avec un simple exemple de transaction bancaire. Voici un autre exemple simple qui explique la différence.
Maintenant que nous avons cloué la terminologie, essayons de répondre à la question initiale.
Étant donné que les conditions de concurrence sont des bogues sémantiques, il n'existe aucun moyen général de les détecter. En effet, il n'y a aucun moyen d'avoir un oracle automatisé qui puisse distinguer le comportement correct du programme incorrect dans le cas général. La détection des races est un problème indécidable.
D'un autre côté, les races de données ont une définition précise qui ne se rapporte pas nécessairement à l'exactitude, et donc on peut les détecter. Il existe de nombreuses variantes de détecteurs de course de données (détection de course de données statique / dynamique, détection de course de données basée sur un jeu de clés, détection de course de données basée sur le passé, détection de course de données hybride). Un détecteur de course de données dynamique de pointe est ThreadSanitizer qui fonctionne très bien dans la pratique.
La gestion des courses de données en général nécessite une certaine discipline de programmation pour induire des fronts entre les accès aux données partagées (soit pendant le développement, soit une fois qu'ils sont détectés à l'aide des outils mentionnés ci-dessus). cela peut être fait à travers des verrous, des variables de condition, des sémaphores, etc. Cependant, on peut également utiliser différents paradigmes de programmation comme le passage de messages (au lieu de la mémoire partagée) qui évitent les courses de données par construction.
la source
Une sorte de définition canonique est « lorsque deux threads accèdent au même emplacement en mémoire en même temps, et qu'au moins un des accès est une écriture ». Dans la situation, le thread "lecteur" peut obtenir l'ancienne ou la nouvelle valeur, selon le thread "qui remporte la course". Ce n'est pas toujours un bogue - en fait, certains algorithmes de bas niveau vraiment poilus le font exprès - mais il devrait généralement être évité. @Steve Gury donne un bon exemple de cas où cela pourrait être un problème.
la source
Une condition de concurrence est une sorte de bug, qui ne se produit qu'avec certaines conditions temporelles.
Exemple: imaginez que vous avez deux fils, A et B.
Dans le fil A:
Dans le fil B:
Si le thread A est préempté juste après avoir vérifié cet objet. A n'est pas nul, B le fera
a = 0
, et lorsque le thread A gagnera le processeur, il fera une "division par zéro".Ce bogue ne se produit que lorsque le thread A est préempté juste après l'instruction if, c'est très rare, mais cela peut arriver.
la source
La condition de concurrence n'est pas seulement liée au logiciel mais également au matériel. En fait, le terme a été initialement inventé par l'industrie du matériel.
Selon wikipedia :
L'industrie du logiciel a utilisé ce terme sans modification, ce qui le rend un peu difficile à comprendre.
Vous devez effectuer un remplacement pour le mapper au monde logiciel:
Ainsi, la condition de concurrence dans l'industrie du logiciel signifie "deux threads" / "deux processus" qui s'affrontent pour "influencer un état partagé", et le résultat final de l'état partagé dépendra d'une certaine différence de synchronisation subtile, qui pourrait être causée par certains ordre de lancement des threads / processus, ordonnancement des threads / processus, etc.
la source
Une condition de concurrence critique est une situation de programmation simultanée où deux threads ou processus simultanés sont en concurrence pour une ressource et l'état final résultant dépend de qui obtient la ressource en premier.
la source
Les conditions de concurrence se produisent dans les applications multi-thread ou les systèmes multi-processus. Une condition de concurrence, à sa base, est tout ce qui fait l'hypothèse que deux choses qui ne sont pas dans le même thread ou processus se produiront dans un ordre particulier, sans prendre de mesures pour s'assurer qu'elles le font. Cela se produit généralement lorsque deux threads transmettent des messages en définissant et en vérifiant les variables membres d'une classe auxquelles les deux peuvent accéder. Il y a presque toujours une condition de concurrence lorsqu'un thread appelle sleep pour donner à un autre thread le temps de terminer une tâche (sauf si ce sommeil est en boucle, avec un mécanisme de vérification).
Les outils de prévention des conditions de concurrence dépendent du langage et du système d'exploitation, mais certains sont communs aux mutex, aux sections critiques et aux signaux. Les mutex sont bons lorsque vous voulez vous assurer que vous êtes le seul à faire quelque chose. Les signaux sont bons lorsque vous voulez vous assurer que quelqu'un d'autre a fini de faire quelque chose. La réduction des ressources partagées peut également aider à prévenir les comportements inattendus
Détecter les conditions de course peut être difficile, mais il y a quelques signes. Le code qui dépend fortement du sommeil est sujet aux conditions de concurrence, alors vérifiez d'abord les appels à dormir dans le code affecté. L'ajout de périodes de sommeil particulièrement longues peut également être utilisé pour le débogage pour essayer de forcer un ordre particulier d'événements. Cela peut être utile pour reproduire le comportement, voir si vous pouvez le faire disparaître en modifiant le timing des choses et pour tester les solutions mises en place. Les mises en veille doivent être supprimées après le débogage.
Le signe de signature que l'on a une condition de concurrence est cependant, s'il y a un problème qui ne se produit que par intermittence sur certaines machines. Les bogues courants seraient les plantages et les blocages. Avec la journalisation, vous devriez être en mesure de trouver la zone affectée et de travailler à partir de là.
la source
Microsoft a en fait publié un article vraiment détaillé sur cette question des conditions de concurrence et des blocages. Le résumé le plus résumé serait le paragraphe de titre:
la source
La situation où le processus dépend de façon critique de la séquence ou du calendrier d'autres événements.
Par exemple, le processeur A et le processeur B ont tous deux besoin de ressources identiques pour leur exécution.
Il existe des outils pour détecter automatiquement la condition de concurrence:
Les conditions de compétition peuvent être gérées par Mutex ou Semaphores . Ils agissent comme un verrou permettant à un processus d'acquérir une ressource en fonction de certaines exigences pour empêcher la condition de concurrence.
Il existe différentes façons d'empêcher la condition de concurrence, comme l' évitement des sections critiques .
la source
Une condition de concurrence critique est une situation indésirable qui se produit lorsqu'un appareil ou un système tente d'effectuer deux ou plusieurs opérations en même temps, mais en raison de la nature de l'appareil ou du système, les opérations doivent être effectuées dans le bon ordre afin d'être fait correctement.
Dans la mémoire ou le stockage de l'ordinateur, une condition de concurrence peut se produire si des commandes de lecture et d'écriture d'une grande quantité de données sont reçues presque au même instant et que la machine tente d'écraser une partie ou la totalité des anciennes données pendant que ces anciennes données sont toujours en cours. lis. Le résultat peut être un ou plusieurs des éléments suivants: un crash informatique, une «opération illégale», une notification et un arrêt du programme, des erreurs de lecture des anciennes données ou des erreurs d'écriture des nouvelles données.
la source
Voici l'exemple classique de solde de compte bancaire qui aidera les débutants à comprendre les threads en Java facilement dans les conditions de concurrence:
la source
Vous pouvez empêcher la condition de concurrence , si vous utilisez des classes "atomiques". La raison en est simplement que le thread ne sépare pas l'opération get and set, l'exemple est ci-dessous:
En conséquence, vous aurez 7 dans le lien "ai". Bien que vous ayez effectué deux actions, mais que les deux opérations confirment le même thread et qu'aucun autre thread n'interfère avec cela, cela ne signifie aucune condition de concurrence!
la source
Essayez cet exemple de base pour mieux comprendre les conditions de concurrence:
la source
Vous ne voulez pas toujours ignorer une condition de concurrence. Si vous avez un indicateur qui peut être lu et écrit par plusieurs threads et que cet indicateur est défini sur "terminé" par un thread afin que l'autre thread arrête le traitement lorsque l'indicateur est défini sur "terminé", vous ne voulez pas de cette "course". condition "à éliminer. En fait, celui-ci peut être qualifié de condition de course bénigne.
Cependant, en utilisant un outil pour la détection de la condition de course, il sera identifié comme une condition de course nuisible.
Plus de détails sur les conditions de compétition ici, http://msdn.microsoft.com/en-us/magazine/cc546569.aspx .
la source
Considérons une opération qui doit afficher le nombre dès que le nombre est incrémenté. c'est-à-dire, dès que CounterThread incrémente la valeur DisplayThread doit afficher la valeur récemment mise à jour.
Production
Ici, CounterThread obtient fréquemment le verrou et met à jour la valeur avant que DisplayThread ne l' affiche. Il existe une condition de course. La condition de concurrence peut être résolue en utilisant la synchronisation
la source
Une condition de concurrence critique est une situation indésirable qui se produit lorsque deux processus ou plus peuvent accéder et modifier les données partagées en même temps, car il y a eu des accès conflictuels à une ressource. Un problème de section critique peut entraîner une condition de concurrence. Pour résoudre une condition critique parmi le processus, nous n'avons supprimé qu'un seul processus à la fois qui exécute la section critique.
la source