Question

Nous avons une base de code vieille de plusieurs années et tous les développeurs d'origine ont disparu depuis longtemps.Il utilise de très nombreux threads, mais sans conception apparente ni principes architecturaux communs.Chaque développeur avait son propre style de programmation multithread, donc certains threads communiquent entre eux à l'aide de files d'attente, certains verrouillent les données avec des mutex, certains se verrouillent avec des sémaphores, certains utilisent les mécanismes IPC du système d'exploitation pour les communications intra-processus.Il n’existe aucune documentation de conception et les commentaires sont rares.C'est un gâchis, et il semble que chaque fois que nous essayons de refactoriser le code ou d'ajouter de nouvelles fonctionnalités, nous introduisons des blocages ou d'autres problèmes.

Alors, est-ce que quelqu'un connaît des outils ou des techniques qui pourraient aider à analyser et documenter toutes les interactions entre les threads ?FWIW, la base de code est C++ sous Linux, mais je serais intéressé d'en savoir plus sur les outils pour d'autres environnements.


Mise à jour

J'apprécie les réponses reçues jusqu'à présent, mais j'espérais quelque chose de plus sophistiqué ou systématique que des conseils qui sont essentiellement "ajouter des messages de journal, déterminer ce qui se passe et le réparer". Il existe de nombreux outils pour analyser et documenter le flux de contrôle dans des programmes à thread unique;n'y a-t-il rien de disponible pour les programmes multithread ?


Voir également Débogage d'applications multithread

Était-ce utile?

La solution

Investissez dans une copie d'Intel VTune et ses outils de profilage de threads.Il vous donnera à la fois une vue au niveau du système et de la source du comportement du thread.Cela ne documentera certainement pas automatiquement la chose pour vous, mais devrait être une réelle aide pour au moins visualiser ce qui se passe dans différentes circonstances.

Je pense qu'il existe une version d'essai que vous pouvez télécharger, cela vaut donc peut-être la peine de l'essayer.Je n'ai utilisé que la version Windows, mais en regardant la page Web de VTune, il existe également une version Linux.

Autres conseils

Pour commencer, je serais tenté d'ajouter des messages de journal de traçage à des points stratégiques de votre application.Cela vous permettra d'analyser la manière dont vos threads interagissent sans risquer que le fait d'observer les threads modifie leur comportement (comme cela pourrait être le cas avec un débogage étape par étape).Mon expérience concerne la plate-forme .NET et mon outil de journalisation préféré serait log4net car il est gratuit, propose de nombreuses options de configuration et, si vous êtes raisonnable dans la façon dont vous implémentez votre journalisation, cela n'entravera pas sensiblement les performances de votre application.Alternativement, il existe la classe Debug (ou Trace) intégrée de .NET dans l'espace de noms System.Diagnostics.

Je me concentrerais d'abord sur les verrous de mémoire partagée (les mutex et les sémaphores), car ils sont les plus susceptibles de causer des problèmes.Regardez quel état est protégé par des verrous, puis déterminez quel état est sous la protection de plusieurs verrous.Cela vous donnera une idée des conflits potentiels.Regardez les situations où le code qui détient un verrou appelle des méthodes (n'oubliez pas les méthodes virtuelles).Essayez d'éliminer ces appels dans la mesure du possible (en réduisant la durée de maintien du verrou).

Étant donné la liste des mutex détenus et une idée approximative de l'état qu'ils protègent, attribuez un ordre de verrouillage (c'est-à-dire que le mutex A doit toujours être pris avant le mutex B).Essayez d'appliquer cela dans le code.

Voyez si vous pouvez combiner plusieurs verrous en un seul si la concurrence n'est pas affectée.Par exemple, si les mutex A et B semblent avoir des blocages et qu'un schéma de commande n'est pas facile à réaliser, combinez-les initialement en un seul verrou.

Cela ne va pas être facile, mais je suis favorable à la simplification du code au détriment de la concurrence pour maîtriser le problème.

C'est un problème vraiment difficile pour les outils automatisés.Vous voudrez peut-être examiner vérification du modèle votre code.Ne vous attendez pas à des résultats magiques :les vérificateurs de modèles sont très limités en termes de quantité de code et de nombre de threads qu'ils peuvent vérifier efficacement.

Un outil qui pourrait fonctionner pour vous est ÉCHECS (même si ce n'est malheureusement que Windows). EXPLOSION est un autre outil assez puissant, mais il est très difficile à utiliser et peut ne pas gérer le C++.Wikipédia répertorie également Vapeur, dont je n'ai jamais entendu parler auparavant, mais il semble que cela pourrait fonctionner pour vous :

StEAM est un vérificateur de modèles pour C++.Il détecte les blocages, les erreurs de segmentation, les variables hors plage et les boucles sans terminaison.

Alternativement, il serait probablement très utile d'essayer de faire converger le code vers un petit nombre de schémas de synchronisation bien définis (et, de préférence, de haut niveau).Mélanger des verrous, des sémaphores et des moniteurs dans la même base de code pose problème.

Une chose à garder à l’esprit lors de l’utilisation de log4net ou d’un outil similaire est qu’ils modifient le timing de l’application et peuvent souvent masquer les conditions de concurrence sous-jacentes.Nous avions du code mal écrit pour déboguer et introduit la journalisation, ce qui a en fait supprimé les conditions de concurrence et les blocages (ou réduit considérablement leur fréquence).

En Java, vous avez le choix entre FindBugs (pour l'analyse statique du bytecode) pour détecter certains types de synchronisation incohérente, ou les nombreux analyseurs de threads dynamiques de sociétés comme Coverity, JProbe, OptimizeIt, etc.

UML ne peut-il pas vous aider ici ?

Si vous effectuez une rétro-ingénierie de votre base de code dans UML, vous devriez alors être capable de dessiner des diagrammes de classes qui montrent les relations entre vos classes.En partant des classes dont les méthodes sont les points d’entrée du thread, vous pouvez voir quel thread utilise quelle classe.D'après mon expérience avec Rose rationnelle, cela pourrait être réalisé par glisser-déposer ;s'il n'y a aucune relation entre la classe ajoutée et les précédentes, alors la classe ajoutée n'est pas directement utilisée par le thread qui a démarré avec la méthode avec laquelle vous avez commencé le diagramme.Cela devrait vous donner des indications sur le rôle de chaque thread.

Cela affichera également les « objets de données » partagés et les objets spécifiques au thread.

Si vous dessinez un grand diagramme de classes et supprimez tous les "objets de données", alors vous devriez pouvoir disposer ce diagramme sous forme de nuages, chaque nuage étant un thread - ou un groupe de threads, à moins que le couplage et la cohésion de la base de code ne soient affreux.

Cela ne vous donnera qu'une partie du puzzle, mais cela pourrait être utile ;J'espère juste que votre base de code n'est pas trop boueuse ou trop "procédurale", auquel cas...

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top