waitforexit visual studio start example ejemplos c# process

visual - ¿Cómo uso programáticamente la palabra clave "usar" en C#?



system.diagnostics c# (3)

try { foreach(string command in S) // command is something like "c:/a.exe" { using(p = Process.Start(command)) { // I literally put nothing in here. } } } catch (Exception e) { // notify of process failure }

La razón por la que funciona es porque cuando ocurre la excepción, la variable p cae fuera del alcance y, por lo tanto, se llama el método Dispose que cierra el proceso. Además, creo que te gustaría separar un hilo para cada comando en lugar de esperar a que termine un ejecutable antes de pasar al siguiente.

Tengo algunos System.Diagnotics.Processes para ejecutar. Me gustaría llamar al método de cierre automáticamente. Aparentemente, la palabra clave "usar" hace esto por mí.

¿Es esta la manera de usar la palabra clave using?

foreach(string command in S) // command is something like "c:/a.exe" { try { using(p = Process.Start(command)) { // I literally put nothing in here. } } catch (Exception e) { // notify of process failure } }

Me gustaría iniciar múltiples procesos para ejecutar al mismo tiempo.


Para referencia: la palabra clave using para objetos IDisposable :

using(Writer writer = new Writer()) { writer.Write("Hello"); }

es solo la sintaxis del compilador Lo que se compila es:

Writer writer = null; try { writer = new Writer(); writer.Write("Hello"); } finally { if( writer != null) { ((IDisposable)writer).Dispose(); } }

using es un poco mejor ya que el compilador le impide reasignar la referencia del escritor dentro del bloque de uso.

Las pautas marco Sección 9.3.1 p. 256 estado:

CONSIDERAR que proporciona el método Close (), además de Dispose (), si close es la terminología estándar en el área.

En su ejemplo de código, el try-catch externo no es necesario (ver arriba).

Usar probablemente no está haciendo lo que desea aquí ya que Dispose () se llama tan pronto como p sale del alcance. Esto no cierra el proceso (probado).

Los procesos son independientes, por lo tanto, a menos que llame a p.WaitForExit() ellos se separan y hacen sus cosas independientemente de su programa.

En contra de lo intuitivo, para un proceso, Close () solo libera recursos pero deja el programa en ejecución. CloseMainWindow () puede funcionar para algunos procesos, y Kill () funcionará para eliminar cualquier proceso. Tanto CloseMainWindow () como Kill () pueden lanzar excepciones, así que ten cuidado si las estás usando en un bloque finally.

Para finalizar, aquí hay un código que espera a que los procesos finalicen, pero no cancela los procesos cuando se produce una excepción. No digo que sea mejor que Orion Edwards, simplemente diferente.

List<System.Diagnostics.Process> processList = new List<System.Diagnostics.Process>(); try { foreach (string command in Commands) { processList.Add(System.Diagnostics.Process.Start(command)); } // loop until all spawned processes Exit normally. while (processList.Any()) { System.Threading.Thread.Sleep(1000); // wait and see. List<System.Diagnostics.Process> finished = (from o in processList where o.HasExited select o).ToList(); processList = processList.Except(finished).ToList(); foreach (var p in finished) { // could inspect exit code and exit time. // note many properties are unavailable after process exits p.Close(); } } } catch (Exception ex) { // log the exception throw; } finally { foreach (var p in processList) { if (p != null) { //if (!p.HasExited) // processes will still be running // but CloseMainWindow() or Kill() can throw exceptions p.Dispose(); } } }

No me molesté en eliminar los procesos porque el código comienza a ser aún más feo. Lea la documentación de msdn para más información.


using(p = Process.Start(command))

Esto compilará, ya que la clase Process implementa IDisposable , sin embargo, realmente desea llamar al método Close .
Lo lógico sería que el método Dispose llamaría Close para usted, y al hurgar en el CLR utilizando el reflector, podemos ver que de hecho lo hace por nosotros. Hasta aquí todo bien.

De nuevo, usando el reflector, miré lo que hace el método Close : libera el identificador de proceso win32 nativo subyacente y borra algunas variables miembro. Esto (liberar recursos externos) es exactamente lo que se supone que debe hacer el patrón ID.

Sin embargo, no estoy seguro de si esto es lo que quiere lograr aquí.

Liberar los identificadores subyacentes simplemente dice a Windows ''Ya no estoy interesado en seguir este otro proceso''. En ningún momento, esto hace que el otro proceso se cierre o que el proceso espere.

Si quieres obligarlos a dejar de fumar, necesitarás utilizar el método p.Kill() en los procesos; sin embargo, ten en cuenta que nunca es una buena idea matar procesos porque no pueden limpiarlos por sí solos, y pueden irse. detrás de archivos corruptos, etc.

Si desea esperar a que se p.WaitForExit() por su cuenta, puede usar p.WaitForExit() ; sin embargo, esto solo funcionará si está esperando un proceso a la vez. Si quieres esperar a todos al mismo tiempo, se vuelve complicado.

Normalmente usaría WaitHandle.WaitAll para esto, pero como no hay forma de obtener un objeto WaitHandle de un System.Diagnostics.Process , no puede hacer esto (en serio, ¿qué tal si estuviera pensando en Microsoft?).

Podrías hacer girar un hilo para cada proceso y llamar a `WaitForExit en esos hilos, pero esta también es la forma incorrecta de hacerlo.

En su lugar, debe usar p / invoke para acceder a la función nativa win32 WaitForMultipleObjects .

Aquí hay una muestra (que he probado, y realmente funciona)

[System.Runtime.InteropServices.DllImport( "kernel32.dll" )] static extern uint WaitForMultipleObjects( uint nCount, IntPtr[] lpHandles, bool bWaitAll, uint dwMilliseconds ); static void Main( string[] args ) { var procs = new Process[] { Process.Start( @"C:/Program Files/ruby/bin/ruby.exe", "-e ''sleep 2''" ), Process.Start( @"C:/Program Files/ruby/bin/ruby.exe", "-e ''sleep 3''" ), Process.Start( @"C:/Program Files/ruby/bin/ruby.exe", "-e ''sleep 4''" ) }; // all started asynchronously in the background var handles = procs.Select( p => p.Handle ).ToArray(); WaitForMultipleObjects( (uint)handles.Length, handles, true, uint.MaxValue ); // uint.maxvalue waits forever }