Programmation en C: le Débogage avec les pthreads
L'une des choses les plus difficiles pour moi d'abord ajuster était ma première expérience intense de la programmation avec les pthreads en C. I a été utilisé pour savoir exactement ce que la prochaine ligne de code à exécuter, et la plupart de mes techniques de débogage centrée autour de cette attente.
Quelles sont les bonnes techniques de débogage avec les pthreads en C? Vous pouvez suggérer des personnels des méthodologies, sans ajouté des outils, des outils que vous utilisez, ou toute autre chose qui vous permettent de déboguer.
P. S. je fais de mon C programmation à l'aide de gcc sous linux, mais ne laissez pas que nécessairement retenir votre réponse
- +1 je pense que c'est une grande question avec beaucoup de " AHA!'-potentiel
Vous devez vous connecter pour publier un commentaire.
Valgrind est un excellent outil pour trouver des conditions de course et des pthreads API abuse. Il garde un modèle de la mémoire de programme (et peut-être de ressources partagées) accès et permet de détecter des verrous manquants même lorsque le bug est bénigne (ce qui signifie qu'il sera complètement inattendue deviennent de moins en moins bénignes à un moment plus tard).
Pour l'utiliser, vous appelez
valgrind --tool=helgrind
, voici son mode d'emploi. Aussi, il estvalgrind --tool=drd
(manuel). Helgrind et DRD utilisation de modèles différents, de sorte qu'ils détectent se chevauchent, mais peut-être différente série de bugs. Les faux positifs peuvent également se produire.De toute façon, valgrind a sauvé d'innombrables heures de débogage (pas tous bien 🙂 pour moi.
L'une des choses qui vous surprendra sur le débogage d'un programme multi-threadé, c'est que vous aurez souvent trouver le bug des changements, ou même disparaît lorsque vous ajoutez printf ou d'exécuter le programme dans le débogueur (familièrement connu comme un Heisenbug).
Dans un programme multi-threadé, un Heisenbug signifie généralement que vous avez un condition de course. Un bon programmeur va chercher les variables partagées ou des ressources qui sont dépendant de l'ordre. Une merde programmeur va essayer de aveuglément fixer avec sleep() consolidés.
Le débogage d'une application multithread est difficile. Un bon débogueur comme GDB (avec en option DDD front-end) pour les *nix de l'environnement ou celui qui est fourni avec Visual Studio sur windows aidera énormément.
Dans la 'pensée' phase, avant de commencer à coder, l'utilisation de la Machine à l'État de concept. Il peut faire la conception beaucoup plus claire.
printf peuvent vous aider à comprendre la dynamique de votre programme. Mais ils encombrent le code source, de sorte que l'utilisation d'une macro DEBUG_OUT() et dans sa définition de l'activer avec un drapeau booléen. Mieux encore, définir/effacer ce drapeau avec un signal que vous envoyez par l'intermédiaire du 'kill-USR1'. Envoyer la sortie vers un fichier de log avec un horodatage.
également envisager l'utilisation de la fonction assert(), puis de les analyser votre core dumps l'utilisation de gdb et ddd.
Mon approche multi-thread, le débogage est similaire à un seul thread, mais plus le temps est généralement consacré à la pensée de phase:
Développer une théorie sur ce qui pourrait être à l'origine du problème.
De déterminer quels types de résultats peuvent être attendus si la théorie est vraie.
Si nécessaire, ajouter du code qui peut infirmer ou de confirmer les résultats et la théorie.
Si votre théorie est vrai, de résoudre le problème.
Souvent, l'expérience prouve que la théorie est l'ajout d'une section critique ou d'un mutex autour du code suspect. Je vais donc essayer de cerner le problème systématiquement le rétrécissement de la section critique. Les sections critiques ne sont pas toujours la meilleure correction (même si elle peut souvent être la solution rapide). Cependant, ils sont utiles pour repérer le "smoking gun'.
Comme je l'ai dit, les mêmes étapes s'appliquent à un seul thread de débogage, mais il est beaucoup trop facile de simplement sauter dans un débogueur et avoir à elle. Multi-thread de débogage nécessite une meilleure compréhension du code, comme j'ai l'habitude de trouver le mode multi-threaded code par l'intermédiaire d'un débogueur ne donne pas quelque chose d'utile.
Aussi, hellgrind est un outil formidable. Intel Fil du Vérificateur effectue une fonction similaire pour Windows, mais coûte beaucoup plus que hellgrind.
J'ai assez bien se développer dans un exclusivement multi-thread, haute performance mondiale de la voici donc, la pratique générale que j'utilise.
De conception - la meilleure optimisation est un meilleur algorithme:
1) vous Briser les fonctions LOGIQUEMENT séparables morceaux. Cela signifie qu'un appel ne "Une" et un SEUL "A"- pas de A, puis B, puis C...
2) PAS d'EFFETS SECONDAIRES: Abolir purement et simplement tous les variables globales et statiques ou pas. Si vous ne pouvez pas complètement abolir les effets secondaires, les isoler à quelques endroits (les concentrer dans le code).
3) Faire autant de composants isolés RÉ-entrant que possible. Cela signifie qu'ils sont apatrides - ils prendre tous leurs intrants, comme les constantes et les manipuler uniquement DÉCLARÉ, logiquement constante des paramètres pour produire la sortie. Passage par valeur, au lieu de référence où vous le pouvez.
4) Si vous avez de l'état, faire une séparation claire entre les apatrides sous-ensembles et l'état réel de la machine. Idéalement, l'état de la machine sera une simple fonction ou une classe de manipuler des composants sans état.
De débogage:
Filetage bugs ont tendance à venir dans 2 grandes saveurs - les races et les blocages. En règle générale, les blocages sont beaucoup plus déterministe.
1) Faites-vous voir de la corruption de données?: OUI => Probablement une course.
2) le bug surviennent sur CHAQUE course ou juste quelques pistes?: OUI => Probablement un blocage (les courses sont généralement non-déterministe).
3) le processus se bloque?: OUI => Il y a un blocage quelque part. Si elle ne se bloque parfois, vous avez probablement une course de trop.
Points d'arrêt agissent souvent comme des primitives de synchronisation EUX-mêmes dans le code, parce qu'ils sont logiquement similaire - ils forcer l'exécution d'un stand dans le contexte actuel jusqu'à un autre contexte (vous) envoie un signal à reprendre. Cela signifie que vous devez afficher tous les points d'arrêt que vous avez dans le code en modifiant son mufti-thread comportement, et les points d'arrêt VA affecter les conditions de course, mais (en général) pas de blocages.
En règle générale, cela signifie que vous devez supprimer tous les points d'arrêt, d'identifier le type de bug, PUIS de les réintroduire à l'essayer et de le corriger. Sinon, ils déforment les choses encore plus.
J'ai tendance à utiliser beaucoup de points d'arrêt. Si vous n'avez pas de soins sur la fonction de thread, mais ne se soucient c'est effets secondaires du bon temps à vérifier peut-être juste avant qu'il ne quitte ou des boucles de retour à son état d'attente ou que ce soit d'autre, c'est en train de faire.
Quand j'ai commencé à faire de la programmation multithread je... arrêté à l'aide de débogueurs.
Pour moi, le point clé est un bon programme, de la décomposition et de l'encapsulation.
Les moniteurs sont le moyen le plus simple erreur de programmation multithread.
Si vous ne pouvez pas éviter les complexes de verrouillage de dépendances, il est facile de vérifier si elles sont cycliques
- attendez jusqu'à ce que le programme se bloque sna vérifier la stacktraces à l'aide de 'pstack'.
Vous pouvez rompre cyclique serrures par l'introduction de nouvelles discussions et de communication asynchrone tampons.
Utilisation des assertions, et assurez-vous d'écrire single thread unittests pour des éléments particuliers de votre logiciel, vous pouvez les exécuter dans le débogueur si vous le souhaitez.