Question

C # .NET 3.5

J'ai une application console qui est appelée par une autre application sur l'ordinateur. Cette application de console fonctionne en permanence et écoute les données sur stdin à partir du " parent " processus.

Toutefois, lorsque le parent est arrêté ou tué, l'application de la console qu'elle a démarrée continue. Dans des circonstances normales, il reste inactif et attend l’entrée de stdin, avec un minimum de ressources. Cependant, dès que le parent disparaît, cette application de la console fait monter en puissance le processeur et prive le noyau sur lequel elle s'exécute d'une utilisation proche de 100%. Cela continue jusqu'à ce que je tue le processus manuellement.

Idéalement, le parent appelant nettoie après lui-même, en particulier puisque cela se produit dans des conditions normales (non exceptionnelles) "Stop". conditions. Malheureusement, ce processus parent est hors de ma portée.

Ma première pensée a été de saisir le parent invoquant à partir de l'application console et de surveiller son PID. Si le processus parent disparaît, l'application de la console se termine elle-même. Actuellement, je le fais par:

Process process = Process.GetCurrentProcess();
m_ParentPID = 0;
using (ManagementObject mgmtObj = new ManagementObject("win32_process.handle='" +     process.Id.ToString() + "'"))
{
    mgmtObj.Get();
    m_ParentPID = Convert.ToInt32(mgmtObj["ParentProcessId"]);
}
string parentProcessName = Process.GetProcessById(m_ParentPID).ProcessName;
Log("Parent Process: " + parentProcessName + Environment.NewLine);

// Create a timer for monitoring self.
Timer timer = new Timer(new TimerCallback(sender =>
{
    if (m_ParentPID != 0)
    {
        Process parent = System.Diagnostics.Process.GetProcessById(m_ParentPID);
        if (parent == null)
        {
            Log("Parent process stopped/killed.  Terminating self.");
            System.Environment.Exit(0);
        }
    }
}));

// Kick on the timer
timer.Change(m_ExitWatcherFrequency, m_ExitWatcherFrequency);

Cela ne fonctionne cependant que partiellement: il arrête la pointe du processeur, mais si je regarde mes processus depuis le moniteur de processus merveilleux de Sysinternals, je vois que DW20.exe est en cours d'exécution - le "Rapport d'erreurs d'application Microsoft". programme. Et c'est juste ... assis, et l'application de la console reste en mémoire.

Que dois-je faire ici pour terminer correctement le processus afin d'éviter ce pic continu de l'UC et cette mémoire inédite? Finalement, cela doit fonctionner sans intervention.

P.S. J'utilise une application en ligne de commande ici en tant que "programme de longue durée". au lieu d’un service Windows ou d’un service Web, car le programme parent ne peut être configuré que pour exécuter une application de ligne de commande pour laquelle il transmet des données via stdin. (pour ceux qui sont curieux, c’est ejabberd, en utilisant une authentification externe).

EDIT:

Le code qui attend l'entrée de stdin est:

// Read data from stdin
char[] charray = new char[maxbuflen];
read = Console.In.Read(charray, 0, 2);

Je mentionne auparavant que lorsque le parent se termine, l'application de la console devient folle sur le processeur. J'ai attaché un débogueur à partir de Visual Studio, et il est, en fait, toujours sur cette ligne Console.In.Read. En théorie, lorsque le minuteur d'auto-surveillance se déclenche et voit que le parent est parti, il tente un System.Environment.Exit (0) lorsque l'autre thread est sur cette ligne Read ().

Était-ce utile?

La solution

On dirait que votre processus se met en boucle, car le flux d’entrée de la console est fermé à la fermeture du parent. Vérifiez-vous la valeur de retour de Console.In.Read ? Il retournera zéro lorsque le flux aura été fermé. À ce stade, sortez de la boucle et laissez votre méthode Main () quitter par elle-même.

Et si vous exécutez plusieurs threads, ils doivent d'abord être terminés, en utilisant Thread.Join ou équivalent.

Autres conseils

Je résoudrais ce problème en ajoutant à votre application console un thread qui surveille fondamentalement la présence de l'application appelante dans la table des processus. Tout cela m'est venu à l'esprit, mais voici un pseudocode:

using System.Thread;
using System.Diagnostics;

main(){
     Thread monitoringThread = new Thread(new ThreadStart(monitor));
     monitoringThread.Name = "Monitor";
     monitoringThread.Start();
}

et dans le moniteur de fonction:

void monitor(){
     Process[] theCallers = Process.GetProcessesByName("CallingProcessName");
     theCallers[0].WaitForExit();
     Process.GetCurrentProcess().Kill();
}

En supposant que vous n’ayez qu’un seul processus appelant dans la liste des processus, dès que ce processus sera terminé, celui-ci le sera également. Vous pouvez également utiliser un code de nettoyage beaucoup plus agréable pour votre propre processus, plutôt que de le laisser se terminer brusquement.

J'aime l'idée de MMR de surveiller le processus parent de l'enfant. Si vous avez un moyen de passer le PID du parent sur la ligne de commande, ce serait encore mieux. Depuis le processus parent, vous pouvez obtenir le PID:

System.Diagnostics.Process.GetCurrentProcess().Id
scroll top