2009-03-04 11 views
32

Soy nuevo en el modelo de subprocesos en .net. Lo usaría para:Inicio del proceso asincrónico y espere a que finalice

  1. iniciar un proceso que trata un archivo (process.StartInfo.FileName = nomArchivo;)
  2. espera para que el usuario cierre el proceso o abandonar el hilo después de algún tiempo
  3. si el usuario cerró el proceso, elimine el archivo

El inicio del proceso y la espera deben realizarse en un subproceso diferente al del subproceso principal, ya que esta operación no debería afectar a la aplicación.

Ejemplo:

Mi aplicación produce un informe HTML. El usuario puede hacer clic derecho en cualquier parte y decir "Ver informe": ahora recupero el contenido del informe en un archivo temporal y lanzo el proceso que maneja los archivos html, es decir, el navegador predeterminado. El problema es que no puedo limpiar, es decir, eliminar el archivo temporal.

+0

Consola ap o WinForms o ASP.NET? – Richard

+0

Consola o WinForms.El proceso que estoy iniciando es local para la máquina. –

+0

Tengo un ejemplo que usa async/await publicado aquí-- http://www.allampersandall.com/2013/03/net-process-async-await – Micah

Respuesta

58

"y la espera debe ser asincrónica" - No estoy tratando de ser gracioso, pero ¿no es eso una contradicción en los términos? Sin embargo, puesto que usted está comenzando un Process, el evento Exited puede ayudar:

ProcessStartInfo startInfo = null; 
Process process = Process.Start(startInfo); 
process.EnableRaisingEvents = true; 
process.Exited += delegate {/* clean up*/}; 

Si desea esperar realmente (tiempo de espera, etc), entonces:

if(process.WaitForExit(timeout)) { 
    // user exited 
} else { 
    // timeout (perhaps process.Kill();) 
} 

Para la espera asincrónico, tal vez sólo tiene que utilizar una hilo diferente?

ThreadPool.QueueUserWorkItem(delegate { 
    Process process = Process.Start(startInfo); 
    if(process.WaitForExit(timeout)) { 
     // user exited 
    } else { 
     // timeout 
    } 
}); 
+0

Tengo una pregunta. Si tengo una función A() {ThreadPool.UnsafeQueueUserWorkItem ((o) => { .... proc.WaitForExit();} ... y en el método principal que tengo de esta manera: Un(); Console.Write ("aa"); por ejemplo ... la cosa es cuando console.write termina su trabajo y el hilo todavía no termina su trabajo ... la página se está cargando y no está esperando que el proceso termine. ¿Qué debo hacer? Gracias chicos – Grace

+0

@Grace es difícil de decir basado sólo en eso ... pero a menos que * esperar * para el hilo de trabajo, ¿no es exactamente lo que * esperar * ver? –

+0

por lo que debería esperar a que el hilo termine desde el método principal? – Grace

4

Pruebe el siguiente código.

public void KickOffProcess(string filePath) { 
    var proc = Process.Start(filePath); 
    ThreadPool.QueueUserWorkItem(new WaitCallBack(WaitForProc), proc); 
} 

private void WaitForProc(object obj) { 
    var proc = (Process)obj; 
    proc.WaitForExit(); 
    // Do the file deletion here 
} 
+1

No estoy seguro de que maneje el mensaje "O abandonar el hilo después de un tiempo" –

0

Probablemente no utilice un proceso separado para abrir un archivo. En cambio, probablemente utilizaría un hilo de fondo (si pensé que la operación iba a llevar mucho tiempo y posiblemente bloquearía el hilo de UI).

private delegate void FileOpenDelegate(string filename); 

public void OpenFile(string filename) 
{ 
    FileOpenDelegate fileOpenDelegate = OpenFileAsync; 
    AsyncCallback callback = AsyncCompleteMethod; 
    fileOpenDelegate.BeginInvoke(filename, callback, state); 
} 

private void OpenFileAsync(string filename) 
{ 
    // file opening code here, and then do whatever with the file 
} 

Por supuesto, esto no es un buen ejemplo de trabajo (no devuelve nada) y no he mostrado cómo la interfaz de usuario se actualiza (usted tiene que utilizar BeginInvoke a nivel de interfaz de usuario porque un subproceso de fondo no puede actualizar el Hilo de interfaz de usuario). Pero, en general, este enfoque es el manejo de las operaciones asincrónicas en .Net.

+0

Lo siento, en realidad quise decir que el proceso debe manejar el archivo, no abrirlo. Reescribí la pregunta. –

0

Usted puede utilizar el evento Exited en la clase de proceso

ProcessStartInfo info = new ProcessStartInfo(); 

info.FileName = "notepad.exe"; 
Process process = Process.Start(info); 

process.Exited += new EventHandler(process_Exited); 
Console.Read(); 

y en ese caso se puede manejar las operaciones que usted ha mencionado

+0

esto no es asincrónico –

17

Adición de una alternativa avanzada a esta vieja pregunta. Si desea esperar a un proceso para salir sin bloquear cualquier tema y todavía soportar tiempos de espera, intente lo siguiente:

public static Task<bool> WaitForExitAsync(this Process process, TimeSpan timeout) 
    { 
     ManualResetEvent processWaitObject = new ManualResetEvent(false); 
     processWaitObject.SafeWaitHandle = new SafeWaitHandle(process.Handle, false); 

     TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>(); 

     RegisteredWaitHandle registeredProcessWaitHandle = null; 
     registeredProcessWaitHandle = ThreadPool.RegisterWaitForSingleObject(
      processWaitObject, 
      delegate(object state, bool timedOut) 
      { 
       if (!timedOut) 
       { 
        registeredProcessWaitHandle.Unregister(null); 
       } 

       processWaitObject.Dispose(); 
       tcs.SetResult(!timedOut); 
      }, 
      null /* state */, 
      timeout, 
      true /* executeOnlyOnce */); 

     return tcs.Task; 
    } 

Una vez más, la ventaja de este enfoque en comparación con la respuesta aceptada es que usted no está bloqueando cualquier hilos, que reduce la sobrecarga de su aplicación.

Cuestiones relacionadas