Pourquoi essayer d’ouvrir un TOpenDialog générant une tonne de threads?

J’ai un formulaire très simple avec un TOpenDialog et un bouton. Lorsque j’appuie sur le bouton, il appelle Execute dans la boîte de dialog. Si je regarde dans le débogueur, le fait d’ouvrir la boîte de dialog crée quelque chose comme 14 threads et ne disparaît pas non plus lorsque je ferme la boîte de dialog.

Quelqu’un a une idée de ce qui se passe avec ça?

Imaginez que vous vouliez montrer à vos amis à quel point le nord-ouest du Pacifique est magnifique. Vous décidez de partir en voyage pour prendre quelques photos du coucher de soleil sur le Pacifique . Ce qui compte vraiment pour vous, ce sont les fichiers d’image qui rentrent chez vous, où ils peuvent être téléchargés sur Facebook. En réalité, la caméra, les objectives et le trépied doivent être transportés par-dessus les Jeux olympiques . Vous devez également amener le photographe (vous-même) qui positionnera l’appareil photo et appuyez sur le déclencheur. Le photographe doit être déplacé et reculé dans un confort relatif, vous prenez donc une place sur laquelle le photographe se reposera pendant le voyage. Ce siège est enfermé dans une boîte en métal shiny avec un tas d’autres pièces en métal, en verre et en caoutchouc dont certaines tournent et effectuent des mouvements de va-et-vient. En fin de compte, environ deux tonnes de choses (et un être humain vivant) faisant un voyage de plusieurs heures, brûlant des litres d’hydrocarbures liquides – dans le but de déplacer quelques informations du rivage vers Internet.

Exactement la même chose se produit avec votre application. Lorsque l’utilisateur souhaite ouvrir un fichier à l’aide de la boîte de dialog “Ouvrir un fichier”, l’utilisateur s’attend à pouvoir:

  • naviguez jusqu’au répertoire contenant le fichier (le répertoire peut être sur un disque dur local ou un CD / DVD / BR ou un lecteur réseau ou une archive, etc. Le support peut être crypté ou compressé, ce qui doit être affiché différemment. branché, pour lequel il peut être nécessaire de demander à l’utilisateur: le support peut nécessiter les informations d’identification de l’utilisateur, qui doivent être demandées);
  • se connecter à un nouveau répertoire en utilisant son URI / UNC (mapper le lecteur);
  • rechercher dans le répertoire des mots-clés;
  • copier / supprimer / renommer certains fichiers;
  • voir la liste des fichiers dans ce répertoire;
  • prévisualiser le contenu de chaque fichier dans le répertoire;
  • sélectionnez le fichier à ouvrir;
  • changer d’avis et décider de ne pas ouvrir le fichier;
  • faire beaucoup d’autres choses liées aux fichiers.

Le système d’exploitation laisse tout cela se produire en donnant essentiellement à votre processus la plupart des fonctionnalités de Windows Explorer. Et une partie doit se produire en arrière-plan, sinon les utilisateurs se plaindront de l’absence de réponse de la boîte de dialog Ouvrir un fichier. La manière évidente d’exécuter certaines tâches en arrière-plan consiste à les exécuter sur des threads différents. Donc c’est ce que nous voyons.

Qu’en est-il des fils laissés derrière, vous demandez? Eh bien, certains d’entre eux sont laissés là pour le cas où l’utilisateur décidera d’ouvrir un autre fichier: cela économise beaucoup de temps, de trafic et de saisie dans ce cas. Cette authentification personnalisée utilisée pour ce processus particulier la dernière fois? — stocké. Les icons de prévisualisation pour ces fichiers PDF embêtants? — toujours là. La longueur et le bitrate pour chaque film du répertoire? – toujours disponible, pas besoin de les ré-parsingr.

Bien sûr, les fils ne sont pas apparus comme par magie. Vérifiez combien de DLL ont été mappées dans le processus. En regardant certains d’entre eux, on peut obtenir une image assez intéressante de la fonctionnalité ajoutée.

Une autre façon intéressante de regarder serait de vider les stacks au moment où chaque thread est créé. Cela montre quelle DLL (et parfois quel object) les a créées. Voici comment un Win64 x64 crée tous les threads. On peut trouver le thread du cadre de l’explorateur en cours de création; une activité OLE qui sera utilisée pour instancier des filtres de fichiers, dont certains peuvent générer des icons de prévisualisation, des superpositions et des info-bulles; peu de threads appartenant au sous-système de recherche; l’énumérateur de périphérique du shell (donc, si l’utilisateur twig un nouveau périphérique, celui-ci apparaîtra automatiquement dans le dialog ouvert); moniteur réseau shell (idem) et d’autres choses.

La bonne nouvelle est que cela se passe rapidement et n’ajoute pas trop de frais à votre processus. La plupart des threads passent le plus clair de leur temps à attendre des événements peu fréquents (comme la clé USB étant branchée), de sorte que le processeur ne passe pas de temps à les exécuter. Chaque thread consum 1 Mo d’espace d’adressage virtuel dans votre processus, mais seulement quelques pages de 4 Ko de mémoire physique réelle. Et la plupart, sinon la totalité de ces DLL n’utilisaient pas de bande passante disque à charger: elles étaient déjà en RAM, elles ont donc été mappées dans votre processus presque gratuitement.

En fin de compte, l’utilisateur a eu beaucoup de fonctionnalités utiles dans une interface utilisateur dynamic, alors que le processus n’a pas été très efficace pour atteindre tout cela.