web-dev-qa-db-fra.com

Comment vérifier si la base de code existante peut une impasse

J'améliore/développer une base de code quelque peu grande, et j'ai introduit multithreading. Mais avec la possibilité d'introduire du code qui pourrait être une impasse, qui est presque impossible à tester avec des tests de boîte noire seule, je veux au moins obtenir un peu de réassurance que mon code est correct. J'ai déjà adhéré aux meilleures pratiques, comme ne jamais avoir plus d'un verrou verrouillé à la fois, verrouillez toujours plusieurs serrures dans le même ordre, etc. Mais il y a des situations où mon code pourrait faire une boucle sur elle-même de manière compliquée, ce qui fait C'est difficile à appliquer.

Je vois que cela pourrait y arriver;

1. Sessions de revue de code lourds avec beaucoup d'yeux et beaucoup de notes prises.

Je pense que cela pourrait toutefois manquer facilement quelques interactions. Et même si la base de code actuelle est prouvée correcte, quelques semaines/mois de peaufinage par différents développeurs feraient toutes les notes et toutes les preuves obsolètes, nécessitant un nouveau cycle de révision, qui est extrêmement pratique.

2: Employer le logiciel pour extraire un graphique d'appel de ma base de code.

J'ai déjà essayé quelques outils et, alors qu'ils produiront de beaux graphiques d'appels, cela prend toujours une inspection manuelle pour voir quelles fonctions verrouillent quoi et comment cette bulle dans le graphique des appels. Et encore une fois, comme avec l'option ci-dessus: Changez la base de code, et il est nécessaire de redoubler les chèques.

3: Ajoutez des balises à toutes les fonctions de prise de verrouillage et de bulles ces balises dans la pile d'appels de fonction.

L'idée étant que chaque serrure unique obtient sa propre balise et que les fonctions prenant plus d'une serrure doivent être étiquetées avec toutes ces balises. De cette façon (potentiellement) les appels de fonction incompatibles devraient se démarquer comme un pouce douloureux.

Celui-ci semble prometteur en ce sens que la base de code est maintenant explicite, de sorte que les modifications apportées au code ne nécessitent pas de nouvelle revue de code (bien, tant que les personnes qui apportent les changements prennent soin de s'occuper du marquage du parcours). Mais la plupart des noms de fonctions deviendront très difficile à manier, certainement les plus grands niveaux qui rassemblent beaucoup de cruft en raison de la quantité de fonctions de verrouillage de niveau inférieure qu'elles appellent. De plus que (dans mon cas) certaines fonctions ne peuvent tout simplement pas être étiquetées de cette manière (constructeurs C++ et opérateurs surchargés, par exemple), je devrais donc renoncer à ces constructions et ajouter des fonctions explicites "init ()" et "copie ()". partout...

Quelqu'un a-t-il une meilleure approche à ce sujet? Ou est une revue de code et adhéré aux meilleures pratiques le mieux que je puisse faire? Si cela importe, j'utilise C++ ici, mais pas la version .NET (donc aucune réflexion et telle).

4
Carl Colijn

Je l'ai déjà adhéré aux meilleures pratiques, comme jamais plus d'un cadenas verrouillé à la fois, toujours verrouiller plusieurs verrous dans le même ordre, etc.

Eh bien, si vous tenez un seul verrou à la fois, le second cas ne se pose jamais.

Si vous faites ont en fait d'acquérir plusieurs verrous, puis en réduisant le nombre de verrous (idéalement un) est mieux que de se assurer de les acquérir dans l'ordre.

Mais il y a des situations où mon code boucle pourrait sur elle-même de manière alambiquée,

si vous avez des données complexes de partage de logique, vous allez avoir du mal.

La meilleure façon de rendre vos données code multi-thread est correct de ne pas partager en premier lieu: factoriser les composants qui peuvent fonctionner de manière asynchrone sur leurs propres données et communiquer avec eux via des files d'attente de messages.

La deuxième est plus facile de diviser votre code en tâches, exécuter à l'aide std::async Ou dans votre propre threadpool avec std::packaged_task Ou similaire - il est plus général que le style fil par composants, mais vous devez prendre certaines précautions sur les dépendances inter-tâches (et les frais généraux de planification peut dominer si vous avez beaucoup de tâches à grain très fin).

Dans les deux cas, vous essayez spécifiquement pour emballer un morceau de données, et niquement code qui peut fonctionner sur elle, en même temps. La communication se fait alors par la propriété en passant explicitement par les files d'attente de messages ou promesses/futures.

Notez que même si vous peut obtenir votre code complexe-exploitation-en-partagé données correctes (et, encore moins, prouver qu'il est correct à une norme raisonnable) , tout le verrouillage, un verrouillage, de tergiverser et cache misses manger souvent loin à tout espéré amélioration de la performance.

7
Useless

Si vous ne le faites pas déjà, une utilisation stricte de RAII peut aider à verrouiller plus déterministe. Les seules fonctions autorisées à verrouiller quoi que ce soit les constructeurs et les seules fonctions qui déverrouillent sont des destructeurs.

Cela pourrait bien se retrouver avec la création d'une classe "casier" dont la seule fonction est de gérer une serrure. La création d'un objet de casier verrouille la ressource et détruisant l'objet le déverrouille à nouveau. Si une fonction souhaite utiliser un objet protégé, créez simplement un objet de casier comme une variable locale dans cette fonction. Raii prend soin du reste.

L'utilisation stricte de RAII empêche les verrous à gauche verrouillés par accident, en particulier si le code prend un chemin inattendu. Cela inclut des exceptions.

1
Simon B

Modélisation avec assistant de preuve, telle que TLA + . Vous pouvez modéliser des comportements, des protocoles, des algorithmes, et il peut rechercher des blocages, des conditions de course, etc. Il existe un certain nombre de guides sur le Web, tels que https://learntla.com/introduction

Les grands fournisseurs de services cloud utilisent TLA + pour vérifier leurs systèmes - ils ont trouvé des bogues très obscurs dans de nombreuses zones qui font cela, au-delà de simples tests. Voir http://cacm.acm.org/magazines/2015/4/184701-how-amazon-web-services-Utilisation-formal-methods/fulltext

0
Erik Eidt

Vous pourriez trouver Annotations d'analyse de sécurité du fil d'intérêt. À condition que vous puissiez structurer votre code afin que le modèle convient, il offre un moyen peu coûteux de vérifier que les choses vont bien. (Les chèques sont également dans GCC.)

0
Bruce Stephens