Pregunta

C # .NET 3.5

Tengo una aplicación de consola que está siendo llamada por otra aplicación en la computadora. Esta aplicación de consola se ejecuta continuamente y escucha los datos en stdin del '' padre '' proceso.

Sin embargo, cuando el padre se detiene o se cancela, la aplicación de la consola que inició continúa. En circunstancias normales, se sienta y permanece inactivo esperando la entrada de stdin, utilizando recursos mínimos. Sin embargo, tan pronto como el padre se va, esta aplicación de consola aumenta la CPU y hace que el núcleo se ejecute con una utilización cercana al 100%. Esto continúa hasta que mato el proceso manualmente.

Lo ideal es que el padre que llama se limpie después de sí mismo, especialmente porque esto ocurre en condiciones normales (no excepcionales) " detener " condiciones Desafortunadamente, este proceso de padres está fuera de mis manos.

Mi primer pensamiento fue agarrar al padre que invoca desde la aplicación de la consola y monitorear su PID. Si el proceso principal desaparece, la aplicación de la consola terminaría por sí misma. Actualmente, estoy haciendo esto por:

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

Sin embargo, esto solo funciona en parte: detiene el pico de CPU, pero si miro mis procesos desde el maravilloso monitor de procesos de Sysinternals, puedo ver DW20.exe ejecutándose: el "Informe de errores de aplicaciones de Microsoft". programa. Y simplemente ... se sienta allí, y la aplicación de la consola permanece en la memoria.

¿Qué debo hacer aquí para terminar correctamente el proceso para evitar este pico continuo de CPU y memoria inédita? Eventualmente, esto debe ejecutarse sin intervención.

P.S. Estoy usando una aplicación de línea de comandos aquí como un " programa de ejecución larga " en lugar de un servicio de Windows o servicio web porque el programa principal solo puede configurarse para ejecutar una aplicación de línea de comandos para la cual pasa datos a través de la entrada estándar. (para aquellos que tienen curiosidad, esto es ejabberd, usando autenticación externa).

EDITAR:

El código que espera la entrada de la entrada estándar es:

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

Mencioné antes que cuando el padre termina, la aplicación de la consola se vuelve loca en la CPU. Le adjunté un depurador desde Visual Studio y, de hecho, todavía está en esa línea Console.In.Read. Entonces, en teoría, cuando el temporizador de autocontrol se dispara y ve que el padre se ha ido, intenta un System.Environment.Exit (0) cuando el otro hilo está en esa línea de Lectura ().

¿Fue útil?

Solución

Parece que su proceso está entrando en un ciclo duro debido a que la secuencia de entrada de la consola se cierra cuando el padre sale. ¿Está comprobando el valor de retorno de Console.In.Read ? Volverá a cero cuando la secuencia se haya cerrado. En ese punto, salga del bucle y deje que su método Main () salga solo.

Y si está ejecutando varios subprocesos, primero deberán finalizarlos, utilizando Thread.Join o equivalente.

Otros consejos

Resolvería esto agregando un subproceso a la aplicación de la consola que básicamente monitorea la presencia de la aplicación que llama en la tabla de procesos. Todo esto está fuera de mi cabeza, pero aquí hay un pseudocódigo:

using System.Thread;
using System.Diagnostics;

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

y en el monitor de funciones:

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

Suponiendo que solo tenga un proceso de llamada en la lista de procesos, tan pronto como finalice ese proceso, este también lo hará. También puede poner un código de limpieza mucho más agradable para su propio proceso, en lugar de tener que terminar de manera abrupta.

Me gusta la idea de mmr de ver el proceso padre desde el niño. Si tiene una manera de pasar el PID de los padres en la línea de comando, eso sería aún mejor. Desde el interior del proceso principal, puede obtener el PID:

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