Domanda

C # .NET 3.5

Ho un'applicazione console che viene chiamata da un'altra applicazione sul computer. Questa app della console funziona ininterrottamente e ascolta i dati su stdin da " parent " processi.

Tuttavia, quando il genitore viene arrestato o ucciso, l'app console avviata continua. In circostanze normali, rimane inattivo in attesa di input da stdin, utilizzando risorse minime. Tuttavia, non appena il genitore si allontana, questa app console aumenta la CPU e fa morire di fame il core su cui è in esecuzione con un utilizzo prossimo al 100%. Questo continua fino a quando non uccido manualmente il processo.

Idealmente, il genitore chiamante dovrebbe ripulire dopo se stesso, in particolare poiché ciò sta accadendo in condizioni normali (non eccezionali) "stop". condizioni. Sfortunatamente, questo processo genitore è fuori dalle mie mani.

Il mio primo pensiero è stato quello di catturare il genitore che invoca dall'interno della console e monitorare il suo PID. Se il processo genitore si interrompe, l'app console si chiuderebbe da sola. Attualmente lo sto facendo tramite:

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);

Questo funziona solo in parte - interrompe il picco della CPU, ma se guardo i miei processi dal meraviglioso monitor di processo Sysinternals, posso vedere DW20.exe in esecuzione - la "Segnalazione errori applicazioni Microsoft" " programma. Ed è solo ... è lì, e l'app console rimane in memoria.

Cosa devo fare qui per terminare correttamente il processo per evitare questo picco continuo di CPU e memoria inedita? Alla fine questo deve essere eseguito senza intervento.

P.S. Sto usando un'applicazione da riga di comando qui come "programma di lunga durata" anziché un servizio Windows o un servizio Web perché il programma padre può essere configurato per eseguire solo un'app della riga di comando per la quale passa i dati tramite stdin. (per coloro che sono curiosi, questo è ejabberd, usando l'autenticazione esterna).

EDIT:

Il codice che attende input da stdin è:

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

Ho già detto che quando termina il genitore, l'app console impazzisce sulla CPU. Ho collegato un debugger ad esso da Visual Studio, ed è, infatti, ancora seduto su quella riga Console.In.Read. In teoria, quindi, quando il timer di automonitor si innesca e vede che il genitore è scomparso, tenta un System.Environment.Exit (0) quando l'altro thread si trova su quella riga Read ().

È stato utile?

Soluzione

Sembra che il tuo processo stia andando in un hard loop a causa della chiusura del flusso di input della console quando il genitore esce. Stai controllando il valore restituito da Console.In.Read ? Restituirà zero quando il flusso è stato chiuso. A quel punto, esci dal ciclo e lascia che il tuo metodo Main () esca da solo.

E se stai eseguendo più thread, dovranno prima essere completati, usando Thread.Join o equivalente.

Altri suggerimenti

Lo risolverei aggiungendo un thread all'app della tua console che sostanzialmente monitora la presenza dell'app chiamante nella tabella dei processi. Questo è tutto al di sopra della mia testa, ma ecco alcuni pseudocodici:

using System.Thread;
using System.Diagnostics;

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

e nel monitor funzioni:

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

Supponendo che tu abbia un solo processo di chiamata nell'elenco dei processi, non appena termina quel processo, anche questo avrà successo. Puoi anche inserire un codice di pulizia molto più bello per il tuo processo, piuttosto che farlo terminare bruscamente.

Mi piace l'idea di mmr di guardare il processo genitore dal bambino. Se hai un modo per passare il PID del genitore sulla riga di comando, sarebbe ancora meglio. Dall'interno del processo padre, puoi ottenere il PID:

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