c# - net - no se puede usar await en void
Comienza el proceso asincrónico y espera a que termine (5)
Soy nuevo en el modelo de subprocesos en .net. ¿Qué usarías para:
- iniciar un proceso que maneja un archivo (process.StartInfo.FileName = fileName;)
- esperar a que el usuario cierre el proceso O abandonar el hilo después de un tiempo
- si el usuario cerró el proceso, elimine el archivo
El inicio del proceso y la espera deben realizarse en un hilo diferente al del hilo 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 los contenidos del informe en un archivo temporal y ejecuto 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.
Agregar una alternativa avanzada a esta vieja pregunta. Si desea esperar a que un proceso salga sin bloquear ningún hilo y todavía admite 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;
}
De nuevo, la ventaja de este enfoque en comparación con la respuesta aceptada es que no está bloqueando ningún subproceso, lo que reduce la sobrecarga de su aplicación.
Probablemente no use 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, este no es un buen ejemplo de trabajo (no devuelve nada) y no he mostrado cómo se actualiza la UI (tienes que usar BeginInvoke en el nivel de UI porque un hilo de fondo no puede actualizar el hilo de UI). Pero, en general, este enfoque es el manejo de las operaciones asincrónicas en .Net.
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
}
Puede usar el evento Exited
en la clase Process
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 puedes manejar las operaciones que mencionaste
"y esperar debe ser asincrónico" - No intento ser gracioso, pero ¿no es eso una contradicción en los términos? Sin embargo, dado que está iniciando un Process
, el evento Exited
puede ayudar:
ProcessStartInfo startInfo = null;
Process process = Process.Start(startInfo);
process.EnableRaisingEvents = true;
process.Exited += delegate {/* clean up*/};
Si realmente quiere esperar (tiempo de espera, etc.), entonces:
if(process.WaitForExit(timeout)) {
// user exited
} else {
// timeout (perhaps process.Kill();)
}
Para esperar la sincronización, ¿tal vez solo use un hilo diferente?
ThreadPool.QueueUserWorkItem(delegate {
Process process = Process.Start(startInfo);
if(process.WaitForExit(timeout)) {
// user exited
} else {
// timeout
}
});