2009-08-19 6 views
3

Je cherche un moyen de redémarrer un thread, que ce soit dans le contexte de ce thread ou à l'extérieur du thread, éventuellement à partir d'un autre processus. (Toutes ces options fonctionneront.) Je suis conscient de la difficulté d'hiberner des processus entiers, et je suis à peu près sûr que ces mêmes difficultés concernent les threads. Cependant, je demande de toute façon dans l'espoir que quelqu'un a un aperçu. Mon but est de mettre en pause, enregistrer dans un fichier, et redémarrer un thread en cours d'exécution de son contexte exact sans modification du code de ce thread, ou plutôt, la modification dans une petite zone - je ne peux pas écrire la sérialisation fonctions dans tout le code. Le bloc de code principal doit être non modifié et ne comportera pas de poignées globales/système (handles de fichiers, sockets, mutex, etc.). Il n'est pas nécessaire d'enregistrer des détails vraiment bas et sales comme des registres de CPU; mais fondamentalement, le tas, la pile et le compteur de programme doivent être sauvegardés, et tout ce qui est nécessaire pour que le thread fonctionne à nouveau logiquement correctement à partir de son point de sauvegarde. L'état résultant du programme ne devrait pas être différent, s'il a été enregistré ou non.Hibernation/redémarrage d'un thread

Ceci est pour un programme de débogage pour un logiciel à haute fiabilité; le but est d'exécuter des simulations du logiciel avec différents scripts pour la saisie, et de pouvoir mettre en pause une simulation en cours puis de la redémarrer plus tard - ou d'amener la simulation à un point de branchement, de l'enregistrer, de faire des copies simulations à partir du point de départ commun. C'est pourquoi le programme principal ne peut pas être modifié.

Le langage de threads principal est en C++, et devrait fonctionner sur Windows et Linux, mais s'il y a un moyen de le faire uniquement sur un système, alors c'est aussi acceptable.

Merci d'avance.

+0

pense que sauvegarder le compteur de programme sans enregistrer les registres du CPU est suffisant pour restaurer l'état du programme en cours? Bien sûr, si le thread n'est pas en cours d'exécution, les valeurs du registre CPU, y compris les PC, seront en pratique quelque part sur la pile, ou peut-être dans une structure de données OS, selon la plate-forme. –

+0

Eh bien, la mémoire doit évidemment être sauvegardée, mais du point de vue de la correction logique, que ce soit dans les registres, le cache, la mémoire ou le paginé, cela n'a pas d'importance. Évidemment, toutes les valeurs contenues dans les registres doivent être sauvegardées, car elles constituent l'état du programme, mais le fait qu'elles existent dans les registres (plutôt que dans le cache, la mémoire ou le disque dur) n'a pas d'importance. –

Répondre

0

Comme tout l'espace d'adressage logique du programme fait partie du contexte du thread, vous devez mettre en veille tout le processus.

Si vous pouvez garantir que le thread n'utilise que des variables locales, vous pouvez sauvegarder sa pile. Il est facile de suspendre un thread avec pthreads, mais je ne vois pas comment vous pourriez accéder à sa pile de l'extérieur alors.

2

Les threads s'exécutent dans le contexte d'un processus. Donc, si vous voulez faire quelque chose comme persister un état de thread sur le disque, vous devez "hiberner" tout le processus.

Vous devrez sérialiser l'ensemble des données de processus. Et vous aurez besoin de stocker le point d'exécution du thread en cours. Je pense que la sérialisation du processus est faisable (consultez boost :: serialize) mais le point d'arrêt du thread est beaucoup plus difficile. Je voudrais mettre des endroits où il peut être arrêté par le code, mais comme vous le dites, vous ne pouvez pas modifier le code. En raison de ce problème, vous envisagez de virtualiser la plate-forme sur laquelle l'application s'exécute et d'utiliser sa fonctionnalité de suspension pour mettre en pause l'ensemble de l'application. Vous trouverez peut-être plus d'informations sur la façon de procéder dans les fonctionnalités du fournisseur de virtualisation, par exemple Xen.

3

Je pense que ce que vous demandez est beaucoup plus compliqué que vous ne le pensez. Je ne suis pas trop familier avec la programmation Windows, mais voici quelques-unes des difficultés que vous rencontrerez dans Linux.

Un thread enregistré peut uniquement être restauré à partir du processus racine qui a généré le thread à l'origine, sinon les bibliothèques dynamiques seraient rompues. En raison de cette sauvegarde sur le disque est essentiellement vide de sens. La raison en est que les bibliothèques dynamiques sont chargées à différentes adresses chaque fois qu'elles sont chargées. La seule façon de contourner cela serait de prendre le contrôle complet de la liaison dynamique, pas un petit exploit. C'est possible, mais assez effrayant.

Le thread suspendu aura des variables dans le tas. Vous devez être en mesure de trouver tous les globals 'possédés' par le fil. L'état «possédé» de n'importe quelle partie du tas ne peut pas être déterminé. Dans le futur, cela peut être possible avec l'ABI de garbage collection de C++ 0x. Vous ne pouvez pas supposer que la pile entière appartient au thread à suspendre. Le thread principal utilise le tas lors de la création de threads. Le fait de souffler le tas en désérialisant le fil en pause casserait le fil principal.

Vous devez résoudre les problèmes avec les globals. Et pas seulement les globals créés dans les threads. Globals (ou statique) peuvent et sont souvent créés dans les bibliothèques dynamiques.

Il y a plus de ressources dans un programme que de la mémoire. Vous avez des handles de fichiers, des sockets réseau, des connexions à la base de données, etc. Un handle de fichier est juste un nombre. sérialiser sa mémoire est complètement dénué de sens sans le contexte du processus dans lequel le fichier a été ouvert.

Tout cela est dit. Je ne pense pas que le problème de base est impossible, mais que vous devriez envisager une approche différente. Quoi qu'il en soit, pour essayer d'implémenter cela, le thread en pause doit être dans un état connu. J'imagine que le fil à arrêter appelait une fonction de bibliothèque signifiait l'arrêt du processus afin qu'il puisse être repris. Je pense que la fourche d'appel système Linux est votre ami. Fork reproduit parfaitement un processus. Avoir le système courir au point et à la fourchette désirés. Une fourchette attend pour en fourrer d'autres. La deuxième branche exécute un ensemble d'entrées.

une fois qu'il a terminé la première fourchette à nouveau pour. Encore une fois, la deuxième fourche peut exécuter un autre jeu d'entrée.

continuer ad infinitum.

0

La façon dont vous devriez faire ceci est via des instantanés de VM; obtenir une copie de VMWare Workstation, puis vous pouvez écrire du code pour automatiser le démarrage/arrêt/instantané de la machine à différents points. Toute autre approche est assez intenable, car si vous êtes capable de geler et débloquer un processus, vous ne pouvez pas reconstruire l'état du système qu'il attend (tout ce que Caspin mentionne comme les handles de fichiers et al.)