Comment détruire automatiquement les processus enfants dans Windows?

Dans l’application Windows C ++, je lance plusieurs processus enfants de longue durée (j’utilise actuellement CreateProcess (…) pour ce faire.

Je souhaite que les processus enfants soient automatiquement fermés si mon processus principal plante ou est fermé.

En raison de l’exigence que cela doit fonctionner pour un plantage du “parent”, je pense que cela devrait être fait en utilisant une API / fonctionnalité du système d’exploitation. Pour que tous les processus “enfants” soient nettoyés.

Comment puis-je faire cela?

L’API Windows prend en charge les objects appelés “Objets du travail”. Le code suivant crée un “job” configuré pour arrêter tous les processus à la fin de l’application principale (lorsque ses descripteurs sont nettoyés). Ce code ne doit être exécuté qu’une seule fois .:

HANDLE ghJob = CreateJobObject( NULL, NULL); // GLOBAL if( ghJob == NULL) { ::MessageBox( 0, "Could not create job object", "TEST", MB_OK); } else { JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 }; // Configure all child processes associated with the job to terminate when the jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; if( 0 == SetInformationJobObject( ghJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli))) { ::MessageBox( 0, "Could not SetInformationJobObject", "TEST", MB_OK); } } 

Ensuite, lorsque chaque processus enfant est créé, exécutez le code suivant pour lancer chaque enfant chaque processus et l’append à l’object de travail:

 STARTUPINFO info={sizeof(info)}; PROCESS_INFORMATION processInfo; // Launch child process - example is notepad.exe if (::CreateProcess( NULL, "notepad.exe", NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo)) { ::MessageBox( 0, "CreateProcess succeeded.", "TEST", MB_OK); if(ghJob) { if(0 == AssignProcessToJobObject( ghJob, processInfo.hProcess)) { ::MessageBox( 0, "Could not AssignProcessToObject", "TEST", MB_OK); } } // Can we free handles now? Not sure about this. //CloseHandle(processInfo.hProcess); CloseHandle(processInfo.hThread); } 

REMARQUE: Voir AssignProcessToJobObject renvoie toujours “access denied” sur Vista si vous rencontrez des problèmes d’access refusé avec AssignProcessToObject () sur Vista.

Une solution quelque peu hackeuse consisterait à associer le processus parent à chaque enfant en tant que débogueur (utilisez DebugActiveProcess ). Lorsqu’un débogueur se termine, tous ses processus de débogage sont également terminés.

Une meilleure solution (en supposant que vous ayez également écrit les processus enfants) serait que les processus enfants surveillent le parent et quittent le processus s’il disparaît.

Windows Job Objects semble être un bon sharepoint départ. Le nom de l’object de travail doit être connu ou transmis aux enfants (ou hériter du descripteur). Les enfants doivent être avertis lorsque le parent meurt, soit à cause d’un “battement de coeur” IPC ayant échoué, soit simplement de WFMO / WFSO sur le handle de processus du parent. À ce moment-là, tout processus enfant pourrait terminer TermianteJobObject pour faire tomber tout le groupe.

Vous pouvez garder un processus de surveillance distinct en cours d’exécution. Sa seule tâche consiste à surveiller l’espace de processus actuel pour détecter les situations que vous décrivez. Il pourrait même relancer l’application d’origine après un crash ou fournir différentes options à l’utilisateur, collecter des informations de débogage, etc.

Vous devrez probablement garder une liste des processus que vous démarrez et les tuer un par un lorsque vous quittez votre programme. Je ne suis pas sûr des détails de faire cela en C ++, mais cela ne devrait pas être difficile. La partie difficile serait probablement de s’assurer que les processus enfants sont arrêtés en cas de plantage d’une application. .Net a la capacité d’append une fonction qui est appelée lorsqu’une exception non gérée se produit. Je ne suis pas sûr que C ++ offre les mêmes capacités.

Vous pouvez encapsuler chaque processus dans un object C ++ et en conserver une liste globale. Les destructeurs peuvent arrêter chaque processus. Cela fonctionnera très bien si le programme se ferme normalement, mais s’il plante, tous les paris sont désactivés.

Voici un exemple approximatif:

 class myprocess { public: myprocess(HANDLE hProcess) : _hProcess(hProcess) { } ~myprocess() { TerminateProcess(_hProcess, 0); } private: HANDLE _hProcess; }; std::list allprocesses; 

Ensuite, chaque fois que vous en lancez un, appelez allprocessess.push_back (hProcess);

Juste du haut de ma tête:

  • Avez-vous envisagé d’utiliser des threads au lieu de processus?
  • Essayez de passer le handle du thread / processus principal aux processus enfants et demandez-leur d’attendre sur ce handle. Cela fonctionne pour les threads, car l’attente sur un handle de thread attend que ce thread se termine et quitte. Pas trop sûr si cela fonctionnera pour les processus, devrait vérifier MSDN pour le vérifier.