Devrais-je m'occuper de conditions de course qui n'ont presque certainement aucune chance de se produire?


52

Considérons quelque chose comme une application d'interface graphique où le thread principal met à jour l'interface utilisateur presque instantanément, et un autre thread interroge des données sur le réseau ou quelque chose qui prend 5 à 10 secondes pour terminer le travail.

J'ai reçu de nombreuses réponses différentes à ce sujet, mais certaines personnes disent que s'il s'agit d'une situation critique d'une impossibilité statistique, ne vous inquiétez pas du tout, mais d'autres ont dit que s'il y avait même une marge de 10 -53 % (je vous n’avez pas de chiffres, c’est ce que j’ai entendu) d’une certaine magie vaudou se produisant en raison de conditions de concurrence critique, obtenez / libérez toujours des verrous sur le fil qui en a besoin.

Quelles sont vos pensées? Est-ce une bonne pratique de programmation de gérer la situation de concurrence critique dans de telles situations statistiquement impossibles? ou serait-il totalement inutile ou même contre-productif d'ajouter plus de lignes de code pour empêcher la lisibilité?


21
Quand les gens déclarent de telles chances, pourquoi personne ne pose-t-il des questions sur l'éducation de la personne mentionnant ce chiffre? Vous devez avoir une éducation formelle en statistiques avant de pouvoir sauvegarder un chiffre comme celui-là.
Pieter B

27
En tant que physicien, p <1E-140 signifie p = 0. Ça ne va pas arriver dans cet univers. 0.000000000000000000000000000000000000000000000000000000001% est beaucoup plus grand.
MSalters

15
Assurez-vous que cette situation de concurrence critique ne provoque pas le blocage volontaire de votre application. Cela pourrait être la cause d'un problème de sécurité.
toasted_flakes

27
Une chance sur un million se produit neuf fois sur dix.
Kaz Dragon

27
"presque certainement n'a aucune chance de se produire?" signifie que cela se produit dans la production à 3 heures du matin et probablement très cher.

Réponses:


137

S'il s'agit vraiment d'un événement 1 sur 10 ^ 55, il ne serait pas nécessaire de coder pour cet événement. Cela impliquerait que si vous exécutiez l'opération 1 million de fois par seconde, vous auriez un bogue tous les 3 * 10 ^ 41 ans, ce qui correspond approximativement à 10 ^ 31 fois l'âge de l'univers. Si votre application n'a d'erreur qu'une seule fois sur chaque billion de milliards d'âges de l'univers, c'est probablement assez fiable.

Cependant, je parierais très fort que l'erreur est loin d'être aussi improbable. Si vous pouvez concevoir l’erreur, il est presque certain qu’elle se produira au moins de temps en temps, ce qui vous permet de coder correctement pour commencer. De plus, si vous codez correctement les threads au début pour qu'ils obtiennent et libèrent les verrous de manière appropriée, le code est beaucoup plus facile à gérer dans le futur. Lorsque vous apportez un changement, vous n'avez pas à vous soucier de réanalyser toutes les conditions de concurrence potentielles, de recalculer leurs probabilités et de vous assurer qu'elles ne se reproduiront pas.


66
Je me souviens d'un commentaire que j'avais lu il y a des années mais que je ne trouve pas maintenant "Une chance sur un million est habituellement mardi prochain". +1 pour avoir dit "c'est loin d'être aussi improbable".
Bevan

2
+1 pour le pari. La meilleure façon de gérer les conditions de concurrence est de les éliminer.
Blrfl

10
@Bevan "Une chance sur un million est habituellement mardi prochain" ... à moins que vous ne jouiez à la loterie :)
dasblinkenlight

22
@dasblinkenlight Mais les chances de quelqu'un gagner dans la plupart des loteries approche 100%. Prédire qui , voilà le défi.
Bevan

3
@Bevan: Ce commentaire était exactement ce qui me passait dans la tête lorsque j'ai lu la question - voici la référence: blogs.msdn.com/b/larryosterman/archive/2004/03/30/104165.aspx
Doc Brown du

69

Du point de vue des coûts et des avantages, vous devez écrire du code supplémentaire uniquement lorsque vous en retirez un bénéfice suffisant.

Par exemple, si le pire scénario qui se produirait si un fil de discussion incorrect "remporte la course" est que les informations ne s'affichent pas et que l'utilisateur doit cliquer sur "actualiser", ne vous inquiétez pas de la situation de concurrence critique: devoir écrire beaucoup de code ne vaut pas la peine de réparer quelque chose d'insignifiant.

D'autre part, si la condition de concurrence critique peut entraîner des transferts de fonds incorrects entre comptes bancaires, vous devez vous prémunir contre la condition de concurrence financière, peu importe la quantité de code que vous devez écrire pour résoudre ce problème.


20
+1: Pour faire la distinction entre "Un échec qui ressemble à un échec" et "Un échec qui ressemble à un succès". Une information incorrecte est beaucoup plus grave, selon le domaine.
deworde

2
+1, les résultats de la condition de concurrence peuvent faire toute une différence.
Grant

+1 La conséquence de la situation de concurrence critique devrait être un facteur décisif pour déterminer si elle doit être traitée. Une condition de concurrence critique susceptible de provoquer un crash d'avion est très différente d'une condition pouvant forcer l'utilisateur à rouvrir une application.
Poke

1
+1: Je dirais que les conséquences sont probablement ce que vous devriez analyser et non la probabilité que cela se produise. Si les conséquences ne comptent pas, vous ne devrez peut-être pas gérer la situation de concurrence critique même si elle est très courante.
Leo

1
Mais ne supposez pas que la résolution d'une situation critique signifie automatiquement que vous devez écrire plus de code. Cela pourrait aussi bien signifier supprimer un gros morceau de code buggy et le remplacer par un plus petit morceau de code correct.
JesperE

45

Trouver une condition de concurrence est la partie la plus difficile. Vous avez probablement passé presque autant de temps à écrire cette question qu’il vous aurait fallu pour la résoudre. Ce n'est pas comme si cela le rendait beaucoup moins lisible. Les programmeurs s'attendent à voir le code de synchronisation dans de telles situations et pourraient en fait perdre plus de temps à se demander pourquoi il n'est pas là et si l'ajouter le corrigerait pour résoudre leur bogue sans rapport.

En ce qui concerne les probabilités, vous seriez surpris. L'année dernière, j'avais reçu un rapport de bogue sur l'état des conditions de course que je ne pouvais pas reproduire avec des milliers d'essais automatisés, mais un système d' un client le voyait tout le temps. La valeur commerciale de consacrer 5 minutes à résoudre ce problème maintenant, par opposition à la résolution d'un problème "impossible" lors de l'installation d'un client, facilite grandement le choix.


1
Cela aussi! Évitez de faire réfléchir les autres programmeurs à la résolution de problèmes éventuels lors de la lecture de votre code, en faisant ce qui est nécessaire (même s'il est «peu probable que cela échoue»).
Casey Kuball

Votre remarque est bonne (les corrections apportées maintenant sont plus rapides et moins chères que celles présentées plus tard), sauf que cela ne sera jamais "5 minutes pour résoudre le problème maintenant".
iconoclast

2
+1 pour signaler que la probabilité de situation critique dépend probablement de nombreux facteurs. Même si cela semble peu probable dans votre configuration, cela peut se produire plus fréquemment sur un système client / sur un système d'exploitation différent / dans la prochaine version, etc.
Sleske

27

Obtenez et libérez les serrures. Les probabilités changent, les algorithmes changent. C'est une mauvaise habitude, et quand quelque chose ne va pas, vous ne devez pas vous arrêter et vous demander si vous ne vous trompez pas…


6
+1 pour le changement d'algorithme. À l'heure actuelle, lorsque vous êtes au courant de la situation de concurrence critique, les probabilités sont faibles. Après un an, lorsque vous avez oublié la condition de concurrence critique, vous pouvez modifier votre code, ce qui modifie considérablement le timing et la probabilité d'un bogue.
Phil

13

et un autre thread interroge des données sur le réseau ou quelque chose dont la fin du travail est garantie.

Jusqu'à ce que quelqu'un introduit une couche de mise en cache pour améliorer les performances. Soudainement, cette autre bande de roulement finissait presque instantanément et la situation de concurrence manifeste le plus souvent.

Si cela avait eu lieu il y a quelques semaines, il a fallu environ 2 jours complets de développement pour trouver le bogue.

Fixez toujours les conditions de course si vous les reconnaissez.


8

Simple vs correct.

Dans de nombreux cas, la simplicité l'emporte sur la correction. C'est une question de coût.

De plus, les conditions de course sont des choses désagréables qui ont tendance à ne pas obéir à de simples statistiques. Tout se passe bien jusqu'à ce qu'une autre synchronisation, apparemment sans lien, provoque soudainement votre situation critique dans la moitié des cas. À moins d’activer les journaux ou de déboguer le code, bien sûr.

Une alternative pragmatique à la prévention d'une situation de concurrence critique (qui peut être délicate) peut être de la détecter et de la journaliser (bonus pour échec rapide et précoce). Si cela ne se produit jamais, vous avez peu perdu. Si cela se produit réellement, vous avez une justification solide pour passer le temps supplémentaire à le réparer.


1
+1 pour la journalisation et échouez tôt si le résoudre est trop compliqué.
Martin Ba

Dans de nombreux cas, la simplicité l'emporte sur la complétude. La synchronisation ne figure presque jamais parmi ces cas. Il reviendra presque toujours plus tard pour vous mordre (ou le pauvre gars chargé de maintenir votre code).
Reirab

@reirab je ne suis pas d'accord. Si vous considérez des événements peu fréquents, une défaillance consignée est rentable. Un exemple: si votre application téléphonique a un taux d'échec de 1/100 (plantage) si l'utilisateur change de réseau à un mois de transition exact (1/31 23:59:00 -> 2/1 00:00:00), vous Je n'entendrai probablement jamais parler de ça. Mais alors une chance sur 10/9 de planter une connexion sur un serveur est inacceptable. Ça dépend.
ptyx

7

Si votre condition de course est liée à la sécurité, vous devriez toujours coder pour l'empêcher.

Un exemple courant est les conditions de concurrence avec la création / ouverture de fichiers sous Unix, qui peuvent dans certaines circonstances donner lieu à des attaques par élévation de privilèges si le programme avec la condition de concurrence s'exécute avec des privilèges plus élevés que ceux qui interagissent avec lui, tel qu'un processus de démon système ou pire encore, le noyau.

Même si une situation de concurrence a environ 10% (- 80) chances de se produire de manière aléatoire , il est tout à fait possible qu'un attaquant déterminé ait une chance décente de créer de telles conditions délibérément et artificiellement.


6

Therac-25!

Les développeurs du projet Therac-25 étaient plutôt confiants quant au décalage entre une interface utilisateur et un problème d’interface dans une machine thérapeutique XRAY.

Ils n'auraient pas dû être.

Vous pouvez en apprendre plus sur ce fameux désastre logiciel à l’adresse suivante:

http://www.youtube.com/watch?v=izGSOsAGIVQ

ou

http://en.wikipedia.org/wiki/Therac-25

Votre application risque d’être beaucoup moins sensible à l’échec que les dispositifs médicaux. Une méthode utile consiste à évaluer l'exposition au risque comme le produit de la probabilité d'occurrence et du coût de l'occurrence pendant la durée de vie du produit pour toutes les unités pouvant être produites.

Si vous avez choisi de construire votre code pour qu'il dure (et cela ressemble à vous), vous devriez considérer la loi de Moore qui peut facilement supprimer plusieurs zéros toutes les quelques années à mesure que les ordinateurs à l'intérieur ou à l'extérieur de votre système deviennent plus rapides. Si vous expédiez des milliers d'exemplaires, supprimez plus de zéros. Si les utilisateurs effectuent cette opération quotidiennement (ou mensuellement) pendant des années, en emportez quelques-uns de plus. S'il est utilisé là où la fibre de Google est disponible, quoi alors? Si les ordures de l'interface utilisateur collectent une opération de l'interface graphique moyenne, cela affecte-t-il la course? Utilisez-vous une bibliothèque Open Source ou Windows derrière votre interface graphique? Les mises à jour peuvent-elles affecter le timing?

Les sémaphores, les verrous, les mutex, la synchronisation de barrières sont parmi les moyens de synchroniser les activités entre les threads. Potentiellement, si vous ne les utilisez pas, une autre personne chargée de la maintenance de votre programme pourrait très rapidement changer d'hypothèse sur les relations entre les threads et invalider le calcul de la condition de concurrence critique.

Je recommande que vous synchronisiez explicitement parce que même si vous ne le voyez pas créer un problème, un client peut le faire. En outre, même si votre condition de concurrence n’est jamais remplie, que se passe-t-il si vous ou votre organisation êtes poursuivis en justice pour défendre votre code (comme Toyota était apparenté à la Prius il y a quelques années). Plus votre méthodologie est approfondie, mieux vous vous en tirerez. Il serait peut-être plus agréable de dire "nous nous gardons contre ce cas improbable comme celui-ci ..." plutôt que de dire "nous savons que notre code va échouer, mais nous avons écrit cette équation pour montrer que cela ne se produira pas de notre vivant. Probablement. "

Il semble que le calcul de probabilité vienne de quelqu'un d'autre. Connaissent-ils votre code et le connaissez-vous suffisamment pour avoir confiance qu'aucune erreur n'a été commise? Si je calculais une fiabilité de 99,99997% pour quelque chose, je pourrais aussi repenser à mes cours de statistiques universitaires et me rappeler que je n’obtenais pas toujours 100% et que je reculais de quelques pour cent sur mes propres estimations de fiabilité.


1
+1 pour mention de Therac-25. Beaucoup de leçons importantes ici.
Stuart Marks

Bien que je pense que c'est une bonne réponse, vous pouvez soutenir que votre projet d'interface graphique amateur ne fera sûrement pas mourir les gens si vous ne parvenez pas à éliminer une situation critique.
marktani

Je ne suis pas très partisan pour argumenter, mais si je le pouvais, je pourrais dire que chaque fois que nous écrivons du code, nous devrions l'écrire correctement. Si nous pouvons nous entraîner à extraire les conditions de course de nos projets de loisir où le code est plus simple et que nous sommes peut-être le seul auteur, nous serons d'autant plus prêts lorsque nous aborderons des projets dans lesquels le travail de plusieurs auteurs doit être intégré.
DeveloperDon

4

Serait-il totalement inutile ou même contre-productif d'ajouter plus de lignes de code pour empêcher la lisibilité?

La simplicité n'est bonne que si elle est également correcte. Comme ce code n'est pas correct, les futurs programmeurs l' examineront inévitablement lorsqu'ils rechercheront un bogue associé.

Quelle que soit la façon dont vous le gérez (en le consignant, en le documentant ou en ajoutant des verrous - cela dépend du coût), vous épargnerez du temps aux autres programmeurs lors de la lecture du code.


3

Cela dépend du contexte. Si c'est un jeu iPhone occasionnel, probablement pas. Le système de contrôle de vol pour le prochain véhicule spatial habité, probablement. Tout dépend des conséquences si le «mauvais» résultat se produit, mesurées par rapport au coût estimé pour le réparer.

Il existe rarement une réponse «unique» pour ce type de questions, car il ne s'agit pas de questions de programmation, mais de questions d'économie.


3
"Le système de contrôle de vol du prochain véhicule spatial habité" DÉFINITIF .
deworde

probablement ... certainement ... cela dépend de qui était dans la fusée :-)
GrandmasterB

3

Oui, attendez-vous à l'inattendu. J'ai passé des heures (dans le code des autres peuples ^^) à rechercher des conditions qui ne devraient jamais se produire.

Des choses telles que toujours avoir un autre, toujours avoir un cas par défaut, initialiser des variables (oui, vraiment .. des bugs surviennent à partir de cela), vérifier vos boucles pour des variables réutilisées à chaque itération, etc.

Si vous êtes particulièrement préoccupé par les problèmes de filetage, lisez des blogs, des articles et des livres sur le sujet. Le thème actuel semble être des données immuables.


3

Juste le réparer.

J'ai vu exactement ceci. Un thread parvient à envoyer une requête réseau à un serveur qui effectue une recherche complexe dans la base de données et répond avant que l'autre thread n'entre dans la ligne de code suivante. Ça arrive.

Un client, quelque part, décidera un jour d'exécuter quelque chose qui absorbe tout le temps de calcul du thread "rapide" tout en laissant le thread lent en marche, et vous serez désolé :)


1

Si vous avez reconnu une condition de concurrence improbable, documentez-la au moins dans le code!

EDIT: Je devrais ajouter que je corrigerais ce problème dans la mesure du possible, mais au moment de la rédaction de ce qui précède, aucune autre réponse ne dit explicitement au moins documenter le problème dans le code.


1
Oui, et au moins, essayez de le détecter et de le consigner si cela se produit. IMHO c'est parfaitement bien de ne pas éviter toutes les erreurs. Mais au moins, faites savoir à quelqu'un que cela s'est produit et que votre supposition que cela ne serait pas erroné.
Steve Bennett

0

Je pense que si vous savez déjà comment et pourquoi cela pourrait arriver, vous pouvez aussi vous en occuper. C’est-à-dire si cela ne prend pas beaucoup de ressources.


0

Tout dépend des conséquences d'une situation de concurrence critique. Je pense que les personnes qui ont répondu à votre question sont correctes pour leur travail. Le mien est des moteurs de configuration de routeur. Pour moi, les conditions de concurrence rendent les systèmes immobiles, corrompus ou non configurés, même s’ils disaient que c’était une réussite. J'utilise toujours des sémaphores par routeur afin de ne rien nettoyer à la main.

Je pense que certains de mes codes d'interface graphique sont toujours sujets aux conditions de concurrence, de sorte qu'un utilisateur risque de recevoir une erreur en raison d'une situation de concurrence, demande après un tel événement.


0

Curieusement, j'ai rencontré ce problème récemment. Je n'avais même pas réalisé qu'une condition de concurrence était possible dans mon cas. La situation de concurrence critique ne s'est manifestée que lorsque les processeurs multicœurs sont devenus la norme.

Le scénario était à peu près comme ça. Un pilote de périphérique a déclenché des événements que le logiciel doit gérer. Le contrôle devait revenir au pilote de périphérique dès que possible pour éviter un dépassement du délai d'attente sur le périphérique. Pour ce faire, l'événement a été enregistré et mis en file d'attente dans un thread distinct.

Receive event from device:
{
    Record event details.
    Enqueue event in the queuing thread.
    Acknowledge the event.
}

Queueing thread receives an event:
{
    Retrieve event details.
    Process event.
    Send next command to device.
}

Cela a bien fonctionné pendant des années. Puis, soudainement, cela échouerait dans certaines configurations. Il s'avère que le thread de mise en file d'attente s'exécutait désormais réellement en parallèle du thread de gestion des événements, au lieu de partager le temps d'un seul processeur. Il a réussi à envoyer la commande suivante au périphérique avant que l'événement ait été acquitté, ce qui a provoqué une erreur de séquence.

Etant donné que cela ne concernait qu'un client dans une configuration, j'ai honteusement indiqué Thread.Sleep(1000)le problème. Il n'y a pas eu de problème depuis.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.