2011-11-07 22 views
5

Tengo un formulario de Windows que crea múltiples aplicaciones de consola del mismo programa (que llama program.exe cualquier número de veces) usandomatar limpiamente una aplicación de consola desde el interior de un grupo de aplicaciones de consola

process.start(). 

soy buscando una forma de identificar un funcionamiento específico de la aplicación y matarla limpiamente (es decir, cerrar limpiamente el 5to proceso de program.exe pero dejar todos los otros procesos en ejecución). Soy capaz de identificar cada proceso diferente de program.exe través de las identificaciones que se dieron cuando se iniciaron los procesos, pero no soy capaz de cerrar la aplicación de cualquier otra manera que llamar

process.kill() 

que no realiza un cierre limpio de la aplicación.

creo que no puedo usar

ya que la aplicación no tiene una ventana (que se ejecuta a través de una consola que se ejecuta en segundo plano). Estoy buscando eliminar los procesos haciendo clic en un botón en mi GUI después de seleccionar el proceso que se eliminará de una lista de los procesos que se están ejecutando.

La razón por la que necesito esto es porque necesito cerrar todos los hilos y aspectos pendientes de cada proceso antes de que se cierre.

defino cada nuevo proceso de la siguiente manera,

Process process = new Process(); 
process.StartInfo = info; 

ExecutionDetails details = new ExecutionDetails(run_id, process, info, session_type, strategy_type, name, ExecutionViewModel); 

lock (_runs) 
_runs.Add(run_id, details); // will throw on Add if duplicate id, prevent duplicate 
ExecutionViewModel.NewRun(details); // add to the view model 

process.Start(); 

Dónde run_id es un GUID que identifica a cada proceso.

En una clase separada, tengo el código que se ejecuta a través del proceso al que solo se hace referencia mediante el símbolo del sistema que inicia el programa (es decir, llama al programa, proporciona variables de configuración, etc.).

¿Hay alguna manera de que pueda cerrar los procesos limpiamente? Estaba pensando que tener un evento que se llama cuando quiero matar el proceso podría funcionar, pero hasta ahora no he podido hacer que funcione esa idea, ya que no puedo especificar qué proceso quiero cerrar.

** EDITAR - Mi código para el manejo de eventos que he intentado implementar pero que no está funcionando.

código Ventana principal

public void KillOne() { 
    foreach (var details in _runs.Values) { 
     if(details.IsSelected) { 
      StrategyStateManager.SessionClosed(this, details.RunId); 
       } } } 

Código de StrategyStateManager (Clase media se utiliza para mantener las variables y eventos para utilizar en el programa)

public delegate void StrategyCloseEventHandler(object sender, StrategyCloseEventArgs e); 

    public static void SessionClosed(object sender, Guid id) 
    { 
     if(CloseSession != null) 
      CloseSession(sender, new StrategyCloseEventArgs(id)); 
    } 


public class StrategyCloseEventArgs : EventArgs 
{ 

    private readonly Guid id; 

    public StrategyCloseEventArgs(Guid run_id) 
    { 
     id = run_id; 
    } 

    public Guid GetRunID() 
    { 
     return id; 
    } 

} 

Código de proceso que se inició por la ventana principal

StrategyStateManager.CloseSession += (closeStrategy); 

void closeStrategy(object sender, StrategyCloseEventArgs e) 
    { 
     if (e.GetRunID() == run_id) 
     { 
      strategy.cleanupForShutdown(); 
      DBSaverSimple.shutdownAll(); 
      logger.Warn("Simulation run stopped by user"); 
     } 
    } 

Respuesta

4

La posibilidad que viene inmediatamente a la mente es utilizar un datagrama de difusión que contenga un mensaje de cierre y la identificación del proceso de la que desea cerrar. Cada uno de los procesos de consola escucha los datagramas de difusión en un puerto común. Cuando el programa recibe un datagrama, analiza los datos, verifica el id del proceso pasado con su propia identificación del proceso y, si coinciden, el programa inicia un apagado limpio.

Esto asume, por supuesto, que ha creado una manera para que el programa se cierre de manera limpia.

No se garantiza la recepción de datagramas de transmisión, por supuesto, pero mi experiencia ha sido que son confiables en un solo sistema. Si se encuentra con un problema, puede hacer que su programa principal envíe el datagrama, espere algún tiempo para ver si el programa se ha apagado, y si no, envíe el datagrama nuevamente.

Otra posibilidad es crear un nombre EventWaitHandle para cada proceso que inicie, pasando el nombre de ese evento a la aplicación de la consola en la línea de comandos. El programa de la consola podría tener un hilo que haga un WaitOne en ese evento. Cuando se establece el evento, el programa inicia un apagado limpio. Esto es más confiable que el datagrama de transmisión. Claro, usa otro identificador por proceso, pero eso no será un problema a menos que tengas miles de procesos.

Consulte Send message from one running console app to another para ver un ejemplo del uso de un identificador de espera con nombre para comunicarse entre procesos.

+0

I implimented la Idea EventWaitHandle que sugirió y funcionó muy bien. Gracias – jwb555

+0

¿Downuidor? Es costumbre proporcionar un comentario que proporcione una razón para el voto a la baja. –

1

Parece que va a tener un estado definido en su separ Común código está siendo ejecutado por los subprocesos en que punto desea que termine ese proceso. ¿Por qué no llamas al Process.GetCurrentProcess().Kill(); o incluso al Process.GetCurrentProcess().Close(); al final de la ruta del código?

De esta forma, cuando se termine de ejecutar, se cerrará/se matará y los procesos restantes continuarán ejecutándose como lo consideren conveniente (hasta que ellos también lleguen a su punto de terminación).

+0

No tengo un tiempo definido en el código cuando quiero que termine. La terminación se decide presionando un botón en la GUI. Si uso Process.Kill() terminará el programa y no se cerrará limpiamente y Process.Close() no terminará realmente el proceso, solo pretende liberar la vista "local" en el proceso y los recursos asociados. – jwb555

+0

¿Has probado 'process.CloseMainWindow()'? Si esto proviene de presionar un botón, ciertamente tiene una ventana principal. También puede intentar 'System.Exit()' para cerrar la aplicación. Si se llama dentro del subproceso, * creo * le dará lo que desea. – Kevek

+0

La terminación proviene de una GUI pero el proceso real no tiene una ventana como se define en el símbolo del sistema para iniciar el proceso. Debido a este Process.CloseMainWindow() no hace nada en el proceso. System.Exit() funcionaría para cerrarlo, pero necesito una forma de poder llamarlo en un proceso específico, ya que múltiples se ejecutarán al mismo tiempo, por lo que se necesitaría un evento o alguna otra notificación para llamar al sistema. .Exit(), que hasta ahora no he podido implementar debido a la situación de procesos múltiples. – jwb555

Cuestiones relacionadas