1132 votes

Qu'est-ce qu'une condition de course?

Lors de l'écriture d'applications multithread, l'un des problèmes les plus courants rencontrés sont les conditions de course.

Ma question à la communauté est:

Qu'est-ce qu'une condition de course? Comment les détectez-vous? Comment les gérez-vous? Et enfin, comment les empêchez-vous de se produire?

1422voto

Lehane Points 6776

Une condition de concurrence se produit lorsque deux ou plusieurs threads peuvent accéder à des données partagées et ils essaient de le changer en même temps. Parce que le fil algorithme d'ordonnancement pouvez permuter entre les threads, à tout moment, vous ne savez pas l'ordre dans lequel les threads tentent d'accéder aux données partagées. Par conséquent, le résultat de la variation des données est dépendante sur le thread de l'algorithme d'ordonnancement, c'est à dire les deux fils sont "racing" pour accéder/modifier le données.

Les problèmes surviennent souvent lorsqu'un thread fait un "check-puis-loi" (par exemple "vérifier" si la valeur est X, alors la "loi" de faire quelque chose qui dépend de la valeur de X) et un autre thread fait quelque chose pour la valeur entre le "check" et la "loi". E. g:

if (x == 5) // The "Check"
{
   y = x * 2; // The "Act"

   // If another thread changed x in between "if (x == 5)" and "y = x * 2" above,
   // y will not be equal to 10.
}

Le point de l'être, y pourrait être de 10, ou il pourrait être n'importe quoi, selon qu'un autre thread changé x entre le chèque et la loi. Vous n'avez pas de véritable moyen de savoir.

Afin de prévenir les conditions de compétition, que vous auriez normalement mettre un verrou autour de données partagées pour s'assurer qu'un seul thread peut accéder aux données à la fois. Cela signifierait quelque chose comme ceci:

// Obtain lock for x
if (x == 5)
{
   y = x * 2; // Now, nothing can change x until the lock is released. 
              // Therefore y = 10
}
// release lock for x

230voto

privatehuff Points 926

Une "race condition" quand multithread (ou parallèle) le code d'accès à une ressource partagée pourrait le faire de façon à provoquer des résultats inattendus.

Prenez cet exemple:

for ( int i = 0; i < 10000000; i++ )
{
   x = x + 1; 
}

Si vous aviez 5 threads s'exécutant ce code à la fois, la valeur de x ne SERAIT PAS finir par être de 50 000 000. Il serait, en effet, varier avec chaque exécution.

C'est parce que, pour chaque thread pour incrémenter la valeur de x, ils doivent faire ce qui suit: (simplifié, évidemment)

Récupérer la valeur de x
Ajouter 1 à la valeur de cette
Stocker cette valeur de x

Un filet peut être à n'importe quelle étape de ce processus à tout moment, et ils peuvent les uns les autres quand une ressource partagée est impliqué. L'état de x peut être changé par un autre thread, durant le temps entre x est en cours de lecture et, lorsqu'elle est écrite en arrière.

Disons un thread récupère la valeur de x, mais n'a pas encore stocké encore. Un autre thread peut également récupérer la même valeur de x (car pas de fil a changé encore) et puis ils seraient tous les deux le stockage de la même valeur (x+1) x!

Exemple:

Thread 1: lit x, la valeur est de 7
Thread 1: ajouter 1 à x, la valeur est maintenant de 8
Filetage 2: lit x, la valeur est de 7
Thread 1: les magasins 8 à x
Filetage 2: ajoute 1 à x, la valeur est maintenant de 8
Filetage 2: magasins 8 x

Des conditions de course peut être évité en utilisant une sorte de verrouillage mécanisme avant le code qui accède à la ressource partagée:

for ( int i = 0; i < 10000000; i++ )
{
   //lock x
   x = x + 1; 
   //unlock x
}

Ici, la réponse vient comme 50 000 000 de tous les temps.

Pour en savoir plus sur le verrouillage, de recherche pour: mutex, sémaphore, section critique, ressource partagée.

162voto

Vishal Shukla Points 308

Qu'est ce qu'une Condition?

Vous envisagez d'aller voir un film à 5 pm. Vous vous renseigner sur la disponibilité des billets à 4 pm. Le représentant a dit qu'ils sont disponibles. De vous détendre et d'atteindre le guichet 5 minutes avant le spectacle. Je suis sûr que vous pouvez deviner ce qui se passe: c'est un full house. Le problème, c'est dans la durée entre la vérification et de l'action. Vous m'avez demandé à 4 et a agi à 5. En attendant, quelqu'un d'autre a attrapé les billets. C'est une condition de concurrence - en particulier un "check-puis-loi" scénario de conditions de course.

Comment les détecter?

Religieux de la revue de code, multi-thread tests unitaires. Il n'y a pas de raccourci. Il y a quelques plugin Eclipse qui apparaissent sur le présent, mais rien de stable encore.

Comment gérer et prévenir? La meilleure chose serait de créer sans effets secondaires et apatrides fonctions, utiliser immutables autant que possible. Mais ce n'est pas toujours possible. Donc, à l'aide de java.util.de façon concomitante.atomique, simultanés des structures de données, la synchronisation, et l'acteur en fonction de la simultanéité de l'aide.

La meilleure ressource pour la simultanéité est JCIP. Vous pouvez également obtenir plus de détails sur l'explication ci-dessus ici.

72voto

Baris Kasikci Points 181

Il y a une importante différence technique entre les conditions de course et les données courses. La plupart des réponses semblent faire l'hypothèse que ces termes sont équivalents, mais ils ne le sont pas.

Données course se produit lorsque 2 des instructions d'accès au même emplacement de mémoire, au moins un de ces accès est une écriture et il n'y a pas de passe avant de commander parmi ces accès. Maintenant, ce qui constitue un arrive avant que la commande est sujette à beaucoup de débats, mais en général ulock-lock paires sur le même verrouiller la variable et attendez-paires de signaux sur la même variable de condition induire un passe-avant commande.

Une condition de concurrence est une erreur sémantique. C'est un défaut qui se produit dans le calendrier ou de l'ordre des événements qui ont conduit à des erreurs de programme de comportement.

De nombreuses conditions de course peuvent être (et sont) causée par des données de courses, mais ce n'est pas nécessaire. Comme une question de fait, les données des courses et des conditions de course ne sont ni nécessaire, ni une condition suffisante pour que l'un de l'autre. Ce blog explique également la différence très bien, avec une simple opération bancaire par exemple. Voici un simple exemple qui explique la différence.

Maintenant que nous avons cloué en bas de la terminologie, nous allons tenter de répondre à la question d'origine.

Étant donné que les conditions de course sont sémantique des bugs, il n'existe pas de moyen de les détecter. C'est parce qu'il n'existe aucun moyen d'avoir un système automatisé d'oracle qui permet de distinguer corriger vs incorrect comportement du programme dans le cas général. Course de détection est un problème indécidable.

D'autre part, les données courses ont une définition précise qui ne se rapporte pas nécessairement à la justesse, et donc on peut les détecter. Il y a beaucoup de saveurs de données course détecteurs (statique/dynamique des données course de détection, de serrures de données basée sur la race de détection, passe-avant que les données fondées sur la race de détection des hybrides, les données de la course de détection). Un état de l'art dynamique de données course détecteur est ThreadSanitizer qui fonctionne très bien dans la pratique.

La manipulation des données des courses en général nécessite une certaine discipline de programmation pour induire arrive-avant de bords entre les accès aux données partagées (soit au cours du développement, ou une fois qu'ils sont détectés à l'aide des outils mentionnés ci-dessus). cela peut être fait au moyen de cadenas, les variables de condition, les sémaphores, etc. Cependant, on peut aussi employer différents paradigmes de programmation, comme la transmission de messages (au lieu de la mémoire partagée) qui évitent les données courses par construction.

43voto

Chris Conway Points 24671

Une sorte de définition canonique est " lorsque deux threads accèdent au même emplacement en mémoire en même temps, et au moins l'un des accès est un write ". Dans la situation, le thread "lecteur" peut obtenir l'ancienne valeur ou la nouvelle valeur, en fonction de quel thread "gagne la course". Ce n'est pas toujours un bug - en fait, certains algorithmes de bas niveau très velus le font exprès - mais il devrait généralement être évité. @Steve Gury donne un bon exemple de quand cela pourrait être un problème.

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